Programmatic Uiscrollview with Autolayout

Programmatic UIScrollview with Autolayout

  1. You don't need to create a faux content view, you can add subviews directly to the scroll view (which I prefer). Apple does not recommend creating one, they only suggest that you can.

  2. Subviews of the scroll view shall not rely on the scroll view to determine their sizes, only their positions.

  3. Your constraints must define the left-most, right-most, top-most, and bottom-most edges in order for auto layout to create the content view for you.

When you create a scroll view, you may give its frame the bounds of the controller's view:

scrollView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(scrollView)
scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
scrollView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
scrollView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
scrollView.heightAnchor.constraint(equalTo: view.heightAnchor).isActive = true

You must then set the boundaries of the content view by anchoring its subviews to the edges of the scroll view. To achieve vertical-only scrolling, your top-most view must be anchored to the top of the scroll view and none of the subviews anchored to the leading and trailing edges must exceed the width of the scroll view.

topMostView.translatesAutoresizingMaskIntoConstraints = false
scrollView.addSubview(topMostView)
topMostView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor).isActive = true
topMostView.topAnchor.constraint(equalTo: scrollView.topAnchor).isActive = true
topMostView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
topMostView.heightAnchor.constraint(equalToConstant: 1000).isActive = true

Notice the topMostView does not rely on the scroll view to determine its size, only its position. The content in your scroll view now has a height of 1000 but it won't scroll because nothing is anchored to the bottom of the scroll view. Therefore, do that in your bottom-most view.

bottomMostView.translatesAutoresizingMaskIntoConstraints = false
scrollView.addSubview(bottomMostView)
bottomMostView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor).isActive = true
bottomMostView.topAnchor.constraint(equalTo: topMostView.bottomAnchor).isActive = true
bottomMostView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
bottomMostView.heightAnchor.constraint(equalToConstant: 1000).isActive = true

bottomMostView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor).isActive = true

The last anchor may seem odd because you're anchoring a view that is 1,000 points tall to an anchor that you just anchored to the bottom of the view which is definitely less than 1,000 points tall. But this is how Apple wants you to do it. By doing this, you do not need to create a content view, auto layout does it for you.

Defining the "edge constraints" (left-most, right-most, top-most, bottom-most) goes beyond scroll views. When you create a custom UITableViewCell, for example, using auto layout, defining the four edge constraints (i.e. where the top-most subview is anchored to the top of the cell topMostView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true, the bottom-most subview to the bottom of the cell bottomMostView.topAnchor.constraint(equalTo: self.bottomAnchor).isActive = true, etc.) is how you create self-sizing cells. Defining the edge constraints is how you create any self-sizing view, really.

UIScrollView setup with AutoLayout Programmatically

You don't need either of these lines - remove them:

self.containerView.heightAnchor.constraint(equalTo: self.scrollView.frameLayoutGuide.heightAnchor).isActive = true
self.containerView.heightAnchor.constraint(equalTo: self.scrollView.frameLayoutGuide.heightAnchor).priority = .defaultLow

You have no constraint controlling the height of contentView ... you need to add:

// quizOptionsTableView bottom to contentView bottom with 8-points "padding
self.quizOptionsTableView.bottomAnchor.constraint(equalTo: self.contentView.bottomAnchor, constant: -8).isActive = true

Couple of suggestions...

  • Respect the Safe Area
  • Stick with .leadingAnchor and .trailingAnchor (right now you're mixing in left/right).
  • Group actions together ... that is, do your subview adding in one place, your constraints all together ... your UI element properties all together.
  • Give your UI elements contrasting background colors to make it easy to see the frames.

Very STRONGLY Recommend: use comments!!!!

Take a look at the way I've edited your code:

class SampleViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

let scrollView = UIScrollView()
let titleLabel = UILabel()
let containerView = UIView()
let contentView = UIView()

let questionImageView = UIImageView()
let questionTitleLabel = UILabel()
let questionNumberLabel = UILabel()
let marksLabel = UILabel()
let quizOptionsTableView = UITableView()

let instructionStackView = UIStackView()

let clockImageView = UIImageView()
let timerLabel = UILabel()

override func viewDidLoad() {
super.viewDidLoad()

[scrollView, containerView, contentView, titleLabel, instructionStackView,
questionImageView, questionTitleLabel, questionNumberLabel,
marksLabel, quizOptionsTableView].forEach { v in
v.translatesAutoresizingMaskIntoConstraints = false
}

//self.scrollView.showsVerticalScrollIndicator = false

self.view.addSubview(self.scrollView)
self.scrollView.addSubview(self.containerView)

self.containerView.addSubview(self.titleLabel)
self.containerView.addSubview(self.instructionStackView)
self.containerView.addSubview(self.contentView)

self.contentView.addSubview(self.questionImageView)
self.contentView.addSubview(self.questionTitleLabel)
self.contentView.addSubview(self.quizOptionsTableView)

self.questionTitleLabel.setContentCompressionResistancePriority(.defaultHigh, for: .vertical)

let verticalStackView = UIStackView(frame: .zero)
verticalStackView.axis = .vertical
verticalStackView.addArrangedSubview(self.questionNumberLabel)
verticalStackView.addArrangedSubview(self.marksLabel)
self.questionNumberLabel.setContentHuggingPriority(.defaultHigh, for: .vertical)

let emptyView = UIView(frame: .zero)
emptyView.widthAnchor.constraint(equalToConstant: 40).isActive = true

let horizantalStackView = UIStackView(frame: .zero)
horizantalStackView.axis = .horizontal
horizantalStackView.addArrangedSubview(emptyView)
horizantalStackView.addArrangedSubview(self.clockImageView)
horizantalStackView.addArrangedSubview(self.timerLabel)
horizantalStackView.spacing = 8

self.instructionStackView.addArrangedSubview(verticalStackView)
self.instructionStackView.addArrangedSubview(horizantalStackView)

let safeGuide = view.safeAreaLayoutGuide
let layoutGuide = scrollView.contentLayoutGuide

NSLayoutConstraint.activate([

// all 4 sides of scrollView to view
self.scrollView.topAnchor.constraint(equalTo: safeGuide.topAnchor),
self.scrollView.leftAnchor.constraint(equalTo: safeGuide.leftAnchor),
self.scrollView.rightAnchor.constraint(equalTo: safeGuide.rightAnchor),
self.scrollView.bottomAnchor.constraint(equalTo: safeGuide.bottomAnchor),

// all 4 sides of containerView to scrollView's Content Layout Guide
self.containerView.topAnchor.constraint(equalTo: layoutGuide.topAnchor),
self.containerView.leadingAnchor.constraint(equalTo: layoutGuide.leadingAnchor),
self.containerView.trailingAnchor.constraint(equalTo: layoutGuide.trailingAnchor),
self.containerView.bottomAnchor.constraint(equalTo: layoutGuide.bottomAnchor),

// containerView Width to scrollView's Frame Layout Guide
self.containerView.widthAnchor.constraint(equalTo: self.scrollView.frameLayoutGuide.widthAnchor),

// NO height constraint for containerView

// titleLabel to top of containerView + 16-points "padding"
self.titleLabel.topAnchor.constraint(equalTo: self.containerView.topAnchor, constant: 16),
// titleLabel to leading/trailing of containerView
self.titleLabel.leadingAnchor.constraint(equalTo: self.containerView.leadingAnchor),
self.titleLabel.trailingAnchor.constraint(equalTo: self.containerView.trailingAnchor),

// instructionStackView top to titleLabel bottom with 24-points "padding"
self.instructionStackView.topAnchor.constraint(equalTo: self.titleLabel.bottomAnchor, constant: 24),
// instructionStackView to leading/trailing of containerView with 50-points "padding"
self.instructionStackView.leadingAnchor.constraint(equalTo: self.containerView.leadingAnchor, constant: 50),
self.instructionStackView.trailingAnchor.constraint(equalTo: self.containerView.trailingAnchor, constant: -50),

// clockImageView width and height
self.clockImageView.widthAnchor.constraint(equalToConstant: 46),
self.clockImageView.heightAnchor.constraint(equalToConstant: 46),

// contentView top to instructionStackView bottom + 16-points "padding"
self.contentView.topAnchor.constraint(equalTo: self.instructionStackView.bottomAnchor, constant: 16),
// contentView to leading/trailing of containerView with 50-points "padding"
self.contentView.leadingAnchor.constraint(equalTo: self.containerView.leadingAnchor, constant: 50),
self.contentView.trailingAnchor.constraint(equalTo: self.containerView.trailingAnchor, constant: -50),
// contentView bottom to containerView bottom with 16-points "padding"
self.contentView.bottomAnchor.constraint(equalTo: self.containerView.bottomAnchor, constant: -16),

// questionImageView top/leading/trailing to contentView with 8-points "padding"
self.questionImageView.topAnchor.constraint(equalTo: self.contentView.topAnchor, constant: 8),
self.questionImageView.leadingAnchor.constraint(equalTo: self.contentView.leadingAnchor, constant: 8),
self.questionImageView.trailingAnchor.constraint(equalTo: self.contentView.trailingAnchor, constant: -8),
// questionImageView height constant
self.questionImageView.heightAnchor.constraint(equalToConstant: 170),

// questionTitleLabel top to questionImageView bottom + 8-points "padding"
self.questionTitleLabel.topAnchor.constraint(equalTo: self.self.questionImageView.bottomAnchor, constant: 8),
// questionTitleLabel leading/trailing to contentView with 8-points "padding"
self.questionTitleLabel.leadingAnchor.constraint(equalTo: self.contentView.leadingAnchor, constant: 8),
self.questionTitleLabel.trailingAnchor.constraint(equalTo: self.contentView.trailingAnchor, constant: -8),

// quizOptionsTableView top to questionTitleLabel + 8-points "padding
self.quizOptionsTableView.topAnchor.constraint(equalTo: self.questionTitleLabel.bottomAnchor, constant: 8),
// quizOptionsTableView leading/trailing to contentView with 8-points "padding"
self.quizOptionsTableView.leadingAnchor.constraint(equalTo: self.contentView.leadingAnchor, constant: 8),
self.quizOptionsTableView.trailingAnchor.constraint(equalTo: self.contentView.trailingAnchor, constant: -8),
// quizOptionsTableView height constant
self.quizOptionsTableView.heightAnchor.constraint(equalToConstant: 320),

// quizOptionsTableView bottom to contentView bottom with 8-points "padding
self.quizOptionsTableView.bottomAnchor.constraint(equalTo: self.contentView.bottomAnchor, constant: -8),
])

// UI element properties
titleLabel.numberOfLines = 0
titleLabel.textAlignment = .center
titleLabel.text = "This is the text for the Title Label which should be able to wrap onto multiple lines."

questionTitleLabel.numberOfLines = 0
questionTitleLabel.text = "This is the text for the Question Title Label which should be able to wrap onto multiple lines just like the Title Label."

questionNumberLabel.text = "1"
marksLabel.text = "Marks?"

if let img = UIImage(systemName: "clock.fill") {
clockImageView.image = img
}
if let img = UIImage(systemName: "photo.tv") {
questionImageView.image = img
}

quizOptionsTableView.register(UITableViewCell.self, forCellReuseIdentifier: "c")
quizOptionsTableView.dataSource = self
quizOptionsTableView.delegate = self

// let's give our UI elements some constrasting colors so we can see their frames
view.backgroundColor = .lightGray
scrollView.backgroundColor = .red
containerView.backgroundColor = .systemGreen
contentView.backgroundColor = .systemBlue
titleLabel.backgroundColor = .yellow
questionTitleLabel.backgroundColor = .cyan
marksLabel.backgroundColor = .green
clockImageView.backgroundColor = .systemYellow
questionImageView.backgroundColor = .systemYellow
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 20
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let c = tableView.dequeueReusableCell(withIdentifier: "c", for: indexPath)
c.textLabel?.text = "\(indexPath)"
return c
}

}

Programmatically layed out UIScrollView, and added auto layout to it's subviews, but it does not scroll

When using Autolayout in UIScrollViews you have to pin subviews both to the top and bottom of the scrollview which allows the scrollview to calculate its contentSize.

Adding this line fixes it:

view4.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor, constant: 0).isActive = true

Using AutoLayout and UIScrollView programmatically

The only way I was able to make it work was by adding BottomAnchor to the last UIView inside ContentView. I created a GitHub repo with demo code here

My Swift 4 UIScrollView with autolayout constraints is not scrolling

You can do this with Auto Layout. The secret is to constrain the edges of the containerView to the edges of the scrollView. It's not intuitive, but constraining the edges of the containerView doesn't set the size, it just makes sure that the content size of the scrollView grows as the containerView grows. By setting constraints for the width of the containerView to a constant that is a larger number than the width of the scrollView, the content will scroll horizontally.

Note: When configuring a scrollView this way, you do not set the contentSize of the scrollView. The contentSize will be computed for you by Auto Layout and it will be equal to the size of the containerView. It is important to make sure that the size of the containerView is fully specified by the constraints.

Here's what I changed to make it work:

containerView = UIView()
containerView.backgroundColor = #colorLiteral(red: 0.176470592617989, green: 0.498039215803146, blue: 0.756862759590149, alpha: 1.0)
scrollView.addSubview(containerView)
//containerView.frame = CGRect(x: 0, y: 0, width: 1080, height: 200)
containerView.translatesAutoresizingMaskIntoConstraints = false
containerView.topAnchor.constraint(equalTo:scrollView.topAnchor).isActive = true
containerView.leadingAnchor.constraint(equalTo:scrollView.leadingAnchor).isActive = true
containerView.trailingAnchor.constraint(equalTo:scrollView.trailingAnchor).isActive = true
containerView.bottomAnchor.constraint(equalTo:scrollView.bottomAnchor).isActive = true
containerView.heightAnchor.constraint(equalToConstant: 200).isActive = true
containerView.widthAnchor.constraint(equalToConstant: 1080).isActive = true

Why isn't my content scrolling?

For it to scroll, the containerView must be larger than the scrollView. Your error is that you have set the constraints such that the containerView is the same width and height as the scrollView, and that is why your content isn't scrolling.

If you want it to scroll horizontally, the width of the containerView must be larger than the scrollView's width. You can do this in one of two ways:

  1. Specify an explicit constant width for the containerView that is larger than the scrollView's width.

    OR

  2. Chain the subviews of the containerView from left to right with the left most being constained to the leading edge of the containerView. Fully specify the widths of the subviews, and place distance contraints between the subviews. The rightmost subview must have an offset from the trailing edge of the containerView. By doing this, Auto Layout can compute the width of the containerView and set the contentSize of the scrollView.


Mini project: update

This is a version of your mini project which uses a chain of constrained views to define the containerView's width. The key is the final constraint after the for loop in viewDidLoad() which connects the last button's trailingAnchor (aka startPoint) to the containerView's trailingAnchor. This completes the chain of contraints and buttons which connect the leading edge of the containerView with the trailing edge of containerView. With this, Auto Layout is able to compute the width of the containerView and establish the contentSize of the scrollView.

import UIKit
import PlaygroundSupport

class FilterViewController: UIViewController {
var filterView: UIView!
var scrollView: UIScrollView!
var containerView: UIView!

override func loadView() {
filterView = UIView()
view = filterView
view.backgroundColor = #colorLiteral(red: 0.909803926944733, green: 0.47843137383461, blue: 0.643137276172638, alpha: 1.0)

scrollView = UIScrollView()
scrollView.backgroundColor = #colorLiteral(red: 0.474509805440903, green: 0.839215695858002, blue: 0.976470589637756, alpha: 1.0)
view.addSubview(scrollView)
scrollView.translatesAutoresizingMaskIntoConstraints = false
scrollView.topAnchor.constraint(equalTo: view.topAnchor, constant: 40).isActive = true
scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
scrollView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
scrollView.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.25).isActive = true
scrollView.isScrollEnabled = true

containerView = UIView()
containerView.backgroundColor = #colorLiteral(red: 0.176470592617989, green: 0.498039215803146, blue: 0.756862759590149, alpha: 1.0)
scrollView.addSubview(containerView)
containerView.translatesAutoresizingMaskIntoConstraints = false

// This is key: connect all four edges of the containerView to
// to the edges of the scrollView
containerView.topAnchor.constraint(equalTo: scrollView.topAnchor).isActive = true
containerView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor).isActive = true
containerView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor).isActive = true
containerView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor).isActive = true

// Making containerView and scrollView the same height means the
// content will not scroll vertically
containerView.heightAnchor.constraint(equalTo: scrollView.heightAnchor).isActive = true
}

class Buttons {
let button = UIButton()
init(titleText: String) {
button.backgroundColor = #colorLiteral(red: 0.976470589637756, green: 0.850980401039124, blue: 0.549019634723663, alpha: 1.0)
button.setTitle(titleText, for: .normal)
}
}

override func viewDidLoad() {
super.viewDidLoad()

let b1 = Buttons(titleText: "one")
let b2 = Buttons(titleText: "two")
let b3 = Buttons(titleText: "three")
let b4 = Buttons(titleText: "four")
let b5 = Buttons(titleText: "five")
let buttonArray = [b1, b2, b3, b4, b5]
var startPoint = containerView.leadingAnchor
for btn in buttonArray {
let theBtn = btn.button
containerView.addSubview(theBtn)
theBtn.translatesAutoresizingMaskIntoConstraints = false
theBtn.leadingAnchor.constraint(equalTo: startPoint, constant: 20).isActive = true
theBtn.topAnchor.constraint(equalTo: containerView.topAnchor).isActive = true
theBtn.bottomAnchor.constraint(equalTo: containerView.bottomAnchor).isActive = true
theBtn.widthAnchor.constraint(equalTo: theBtn.heightAnchor).isActive = true
startPoint = theBtn.trailingAnchor
}
// Complete the chain of constraints
containerView.trailingAnchor.constraint(equalTo: startPoint, constant: 20).isActive = true
}
}

let filterViewController = FilterViewController()
PlaygroundPage.current.liveView = filterViewController

How to set subviews with AutoLayout in UIScrollView programmatically?

Here is a SO answer has explained how to do this with auto layout, he has explain perfectly , In here there is vertically textfields are there But in your case it is you have to set Horizontal views constraints.

Alternative

Rather that setting constraints you can set just frame of the subview and set it in Scrollview, And based on orientation you can change frames of the scrolview's subviews.

Your setData Method like,

-(void)setData{

[self layoutIfNeeded];
CGRect mainFrame=scrollView.frame;
CGRect frame;
for (int i=0; i<arrayData.count ; i++)
{
CGRect frame;
frame.origin.x = scrollView.frame.size.width * i;
frame.origin.y = 0;
frame.size = scrollView.frame.size;

frame.origin=CGPointMake(0, 0);
UIView *subview = [[UIView alloc]initWithFrame:frame];
subview.backgroundColor = [self getRandomColor];
[scrollView addSubview:subview];
}
scrollView.contentSize = CGSizeMake(scrollView.frame.size.width * arrayData.count, mainFrame.size.height/2);
}

Now you using NSNotificationCenter you can get notify when device orientation chaged, so in this selector method of it call your setData method,

[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(setData)
name:UIDeviceOrientationDidChangeNotification
object:nil];

Now in you setData method you need remove all subviews because when device changes Orientation it will add new views to your scrollview, so remove all subview from Scrollview before setting its frame,

        [scrollView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];

Make sure you are removing observer from your class like,

- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}

Programmatic use UIStackView in UIScrollview with Autolayout

The key to getting scroll views to work with auto-layout is to make sure you have a complete "chain" of vertical constraints and element heights, and horizontal constraints and element widths.

Here is an example of what I think you are going for (the green "8-pt horizontal line" you see is the scrollView background color, which you see because there is an 8-pt vertical constraint between the topView and bottomView):

Sample Image

Sample Image

The "bottom" gray view has a height constraint of 500-pts, so we can scroll up:

Sample Image

Here is the code to create that:

-(void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.

UIScrollView *scrollView = [UIScrollView new];
UIView *topView = [UIView new];
UIView *bottomView = [UIView new];
UITextView *textView = [UITextView new];
UIStackView *stackView1 = [UIStackView new];
UIStackView *stackView2 = [UIStackView new];

scrollView.backgroundColor = [UIColor greenColor];
topView.backgroundColor = [UIColor redColor];
bottomView.backgroundColor = [UIColor lightGrayColor];
self.view.backgroundColor = [UIColor yellowColor];

scrollView.translatesAutoresizingMaskIntoConstraints = false;
topView.translatesAutoresizingMaskIntoConstraints = false;
bottomView.translatesAutoresizingMaskIntoConstraints = false;
textView.translatesAutoresizingMaskIntoConstraints = false;
stackView1.translatesAutoresizingMaskIntoConstraints = false;
stackView2.translatesAutoresizingMaskIntoConstraints = false;

// don't bounce the scroll view
scrollView.bounces = false;

// we want the textView to auto-size its height, so set it to non-scrolling
textView.scrollEnabled = NO;

// slightly bigger than default font
textView.font = [UIFont systemFontOfSize:18.0];

// stackView properties
stackView1.axis = UILayoutConstraintAxisVertical;
stackView2.axis = UILayoutConstraintAxisVertical;

stackView1.spacing = 5;
stackView1.distribution = UIStackViewDistributionFill;
stackView2.spacing = 5;
stackView2.distribution = UIStackViewDistributionFill;

// add the scrollView to the view
[self.view addSubview:scrollView];

// constrain scroll view to all 4 sides
[NSLayoutConstraint activateConstraints:
@[
[scrollView.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor],
[scrollView.bottomAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.bottomAnchor],
[scrollView.leadingAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.leadingAnchor],
[scrollView.trailingAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.trailingAnchor]
]
];

// add textView and both stack views to topView
[topView addSubview:textView];
[topView addSubview:stackView1];
[topView addSubview:stackView2];

// setup constraints for topView's subviews
[NSLayoutConstraint activateConstraints:
@[

// textView top, leading and trailing to topView with 8-pts "padding"
[textView.topAnchor constraintEqualToAnchor:topView.topAnchor constant:8.0],
[textView.leadingAnchor constraintEqualToAnchor:topView.leadingAnchor constant:8.0],
[textView.trailingAnchor constraintEqualToAnchor:topView.trailingAnchor constant:-8.0],

// textView should be *at least* 200-pts tall, getting taller if enough text is added
[textView.heightAnchor constraintGreaterThanOrEqualToConstant:200.0],

// stackView1 top to text view bottom, leading and trailing to topView with 8-pts "padding"
[stackView1.topAnchor constraintEqualToAnchor:textView.bottomAnchor constant:8.0],
[stackView1.leadingAnchor constraintEqualToAnchor:topView.leadingAnchor constant:8.0],
[stackView1.trailingAnchor constraintEqualToAnchor:topView.trailingAnchor constant:-8.0],

// stackView2 top to stackView1 bottom, leading and trailing to topView with 8-pts "padding"
[stackView2.topAnchor constraintEqualToAnchor:stackView1.bottomAnchor constant:8.0],
[stackView2.leadingAnchor constraintEqualToAnchor:topView.leadingAnchor constant:8.0],
[stackView2.trailingAnchor constraintEqualToAnchor:topView.trailingAnchor constant:-8.0],

// and constrain stackView2 to bottom of topView with 8-pts padding
[stackView2.bottomAnchor constraintEqualToAnchor:topView.bottomAnchor constant:-8.0],

]

];

// now let's add some labels to the stack views
int numLabels = arc4random_uniform(3) + 2;

for (int i = 0; i < numLabels; i++){

UILabel *label = [UILabel new];
label.font = [UIFont systemFontOfSize:20];
label.numberOfLines = 0;
label.translatesAutoresizingMaskIntoConstraints = false;
label.backgroundColor = [UIColor cyanColor];

label.text = [NSString stringWithFormat:@"Label %d\nIn stackView 1 \nwith more than one line", i];

[stackView1 addArrangedSubview:label];

}

numLabels = arc4random_uniform(3) + 2;

for (int i = 0; i < numLabels; i++){

UILabel *label = [UILabel new];
label.font = [UIFont systemFontOfSize:20];
label.numberOfLines = 0;
label.translatesAutoresizingMaskIntoConstraints = false;
label.backgroundColor = [UIColor colorWithRed:1.0 green:0.75 blue:0.5 alpha:1.0]; // light-orange

label.text = [NSString stringWithFormat:@"Label %d\nIn stackView 2 \nwith more than one line", i];

[stackView2 addArrangedSubview:label];
}

Related Topics



Leave a reply



Submit