Reputation:
I have a View where I load buttons dynamically. So I have a for loop to loop through all buttons. Since this is dynamically I want to create the auto layout programmatically. Right now I have the following code:
for var i = 0; i < data.count; i++ {
let button = UIButton.buttonWithType(UIButtonType.System) as! UIButton
button.backgroundColor = UIColor.greenColor()
button.setTitle("Button", forState: UIControlState.Normal)
button.setTranslatesAutoresizingMaskIntoConstraints(false)
self.view.addSubview(button)
let centerXConstraint = NSLayoutConstraint(item: button, attribute: NSLayoutAttribute.CenterX, relatedBy: NSLayoutRelation.Equal, toItem: scrollView, attribute: NSLayoutAttribute.CenterX, multiplier: 1.0, constant: 0)
let centerYConstraint = NSLayoutConstraint(item: button, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: scrollView, attribute: NSLayoutAttribute.Top, multiplier: 1.0, constant:15)
let widthConstraint = NSLayoutConstraint(item: button, attribute: NSLayoutAttribute.Width, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1.0, constant: 200)
let heightConstraint = NSLayoutConstraint(item: button, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1.0, constant:100)
scrollView.addConstraints([centerXConstraint, centerYConstraint, widthConstraint, heightConstraint])
}
This creates the first button and places it 15px under the top bar. The problem I have is how to place the next button 15px under the first one, the third button 15px under the second one etc. Anyone got any ideas?
Upvotes: 2
Views: 5178
Reputation: 22939
Thats definitely possible, but firstly, I should mention it's not required that you add constraints for the buttons' width and height since they have an intrinsic content size (like UILabel
) which depends on attributes such their text and font.
Back to your problem!
Here's the code, the explanation for each step is below:
override func viewDidLoad() {
super.viewDidLoad()
// 1.
var upperView: UIView = scrollView
for i in 0..<data.count {
let button = UIButton.buttonWithType(UIButtonType.System) as! UIButton
button.backgroundColor = UIColor.greenColor()
button.setTitle("Button", forState: UIControlState.Normal)
button.setTranslatesAutoresizingMaskIntoConstraints(false)
// 2.
scrollView.addSubview(button)
// 3.
let attribute: NSLayoutAttribute = i == 0 ? .Top : .Bottom
// 4.
let topEdgeConstraint = NSLayoutConstraint(item: button,
attribute: .Top,
relatedBy: .Equal,
toItem: upperView,
attribute: attribute,
multiplier: 1.0,
constant: 15.0)
let centerXConstraint = NSLayoutConstraint(item: button,
attribute: .CenterX,
relatedBy: .Equal,
toItem: scrollView,
attribute: .CenterX,
multiplier: 1.0,
constant: 0.0)
scrollView.addConstraint(topEdgeConstraint)
scrollView.addConstraint(centerXConstraint)
// 5.
if i == data.count - 1 {
let bottomConstraint = NSLayoutConstraint(item: button,
attribute: .Bottom,
relatedBy: .Equal,
toItem: scrollView,
attribute: .Bottom,
multiplier: 1.0,
constant: -15.0)
scrollView.addConstraint(bottomConstraint)
}
upperView = button
}
}
1. upperView
is used to keep track of the view 'above' the current button. For example, when the first button is created, the upperView
is the UIScrollView
For the second button, upperView
is the first button; for the third button, upperView
is the second button and so on...
2. Your buttons should be added to the UIScrollView
, not the self.view
. Otherwise you'll get the error:
The view hierarchy is not prepared for the constraint...
3. This line selects the attribute on the upperView
that will relate the button
to the upperView
. Here's a picture to demonstrate what I mean:
a) The .Top
of the button is related to the .Top
of the UIScrollView.
b) The .Top
of the button is related to the .Bottom
of the previous UIButton
.
4. Making the top and centre X constraints - that's all pretty self explanatory.
5. For the UIScrollView
to correctly calculate its contentSize
it must have constraints in an unbroken chain from it top to bottom (the top to the bottom, in this case, because it needs to scroll vertically). Therefore, if it's the last UIButton
a constraint from its bottom edge is added to the UIScrollView
's bottom edge.
Hope that helps!
Upvotes: 15