Setting auto layout constraints programmatically on two views in ViewController
You are on the right track. The trick here is that you need to dynamically update the height of tableView
to its contentSize.height
so infoView
will know it should either be vertically expanded or shrunk:
First you define a property that will hold the height constraint:
@property (nonatomic, strong) NSLayoutConstraint *tableViewHeightConstraint;
- (void)viewDidLoad {
...
self.tableViewHeightConstraint = [NSLayoutConstraint constraintWithItem:self.tableView
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:0.0
constant:350.0];
}
Then you can update the height constraint right after tableView knows its contentSize (ex: viewDidAppear:animated
):
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
self.tableViewHeightConstraint.constant = self.tableView.contentSize.height;
[self.view layoutIfNeeded];
}
I created a sample project for you so you can play around with it to have a better understanding about what I intend to do.
swift how to set autolayout programmatically
There are various ways to do this. One approach:
- declare two "constraint" arrays
- one to hold the "narrow view" constraints
- one to hold the "wide view" constraints
- activate / deactivate the constraints as needed
Here is a complete example:
class ChangeLayoutViewController: UIViewController {
let redButton: UIButton = {
let v = UIButton()
v.translatesAutoresizingMaskIntoConstraints = false
v.backgroundColor = .red
v.setTitle("Red Button", for: [])
return v
}()
let blueButton: UIButton = {
let v = UIButton()
v.translatesAutoresizingMaskIntoConstraints = false
v.backgroundColor = .blue
v.setTitle("Blue Button", for: [])
return v
}()
var narrowConstraints: [NSLayoutConstraint] = [NSLayoutConstraint]()
var wideConstraints: [NSLayoutConstraint] = [NSLayoutConstraint]()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(redButton)
view.addSubview(blueButton)
let g = view.safeAreaLayoutGuide
var c: NSLayoutConstraint
// MARK: - narrow orientation
// constrain redButton above blueButton
// constrain redButton leading and trailing to safe-area (with 8-pts on each side)
c = redButton.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 8.0)
narrowConstraints.append(c)
c = redButton.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -8.0)
narrowConstraints.append(c)
// constrain blueButton leading and trailing to safe-area (with 8-pts on each side)
c = blueButton.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 8.0)
narrowConstraints.append(c)
c = blueButton.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -8.0)
narrowConstraints.append(c)
// constrain redButton top 40-pts from safe-area top
c = redButton.topAnchor.constraint(equalTo: g.topAnchor, constant: 40.0)
narrowConstraints.append(c)
// constrain blueButton top 20-pts from redButton bottom
c = blueButton.topAnchor.constraint(equalTo: redButton.bottomAnchor, constant: 20.0)
narrowConstraints.append(c)
// MARK: - wide orientation
// constrain redButton & blueButton side-by-side
// with equal widths and 8-pts between them
// constrain redButton leading 8-pts from safe-area leading
c = redButton.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 8.0)
wideConstraints.append(c)
// constrain blueButton trailing 8-pts from safe-area trailing
c = blueButton.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -8.0)
wideConstraints.append(c)
// constrain blueButton leading 8-pts from redButton trailing
c = blueButton.leadingAnchor.constraint(equalTo: redButton.trailingAnchor, constant: 8.0)
wideConstraints.append(c)
// constrain buttons to equal widths
c = blueButton.widthAnchor.constraint(equalTo: redButton.widthAnchor)
wideConstraints.append(c)
// constrain both buttons centerY to safe-area centerY
c = redButton.centerYAnchor.constraint(equalTo: g.centerYAnchor)
wideConstraints.append(c)
c = blueButton.centerYAnchor.constraint(equalTo: g.centerYAnchor)
wideConstraints.append(c)
// activate initial constraints based on view width:height ratio
changeConstraints(view.frame.width > view.frame.height)
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
// change active set of constraints based on view width:height ratio
self.changeConstraints(size.width > size.height)
}
func changeConstraints(_ useWide: Bool) -> Void {
if useWide {
NSLayoutConstraint.deactivate(narrowConstraints)
NSLayoutConstraint.activate(wideConstraints)
} else {
NSLayoutConstraint.deactivate(wideConstraints)
NSLayoutConstraint.activate(narrowConstraints)
}
}
}
Results:
How to Create layout constraints programmatically
To fix a view to the bottom of the screen you need following constraints to set.
- Leading Constraint with respect of Parent View for - X
- Trailing Constraint with respect of Parent View for - Width
- Bottom Constraint with respect of Parent View for - Y
- Height Constraint attached to self for - Height.
Lets add.
UIView *subView=bottomView;
UIView *parent=self.view;
subView.translatesAutoresizingMaskIntoConstraints = NO;
//Trailing
NSLayoutConstraint *trailing =[NSLayoutConstraint
constraintWithItem:subView
attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual
toItem:parent
attribute:NSLayoutAttributeTrailing
multiplier:1.0f
constant:0.f];
//Leading
NSLayoutConstraint *leading = [NSLayoutConstraint
constraintWithItem:subView
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:parent
attribute:NSLayoutAttributeLeading
multiplier:1.0f
constant:0.f];
//Bottom
NSLayoutConstraint *bottom =[NSLayoutConstraint
constraintWithItem:subView
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:parent
attribute:NSLayoutAttributeBottom
multiplier:1.0f
constant:0.f];
//Height to be fixed for SubView same as AdHeight
NSLayoutConstraint *height = [NSLayoutConstraint
constraintWithItem:subView
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:0
constant:ADHeight];
//Add constraints to the Parent
[parent addConstraint:trailing];
[parent addConstraint:bottom];
[parent addConstraint:leading];
//Add height constraint to the subview, as subview owns it.
[subView addConstraint:height];
Hope this helps.
Cheers.
AutoLayout constraints for programmatically added buttons in a scrollView
I managed to make your code work with three major changes as follows:
1 - Your content view needs to be of type UIView
let view1 = UIView()
This view will hold a UIScrollView (view2) and they have to have their constraints set. On view1 you will be able to set the size of the scroll view, that's why I made view 2 with 0 distance from the super view.
view1.addSubview(view2)
var dictionary = [String: UIView]()
dictionary.updateValue(view1, forKey: "view1")
view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-0-[view1]-0-|", options: NSLayoutFormatOptions(0), metrics: nil, views: dictionary) as [AnyObject])
view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-0-[view1]-0-|", options: NSLayoutFormatOptions(0), metrics: nil, views: dictionary) as [AnyObject])
dictionary = [String: UIView]()
dictionary.updateValue(view2, forKey: "view2")
view1.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-0-[view2]-0-|", options: NSLayoutFormatOptions(0), metrics: nil, views: dictionary) as [AnyObject])
view1.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-0-[view2]-0-|", options: NSLayoutFormatOptions(0), metrics: nil, views: dictionary) as [AnyObject])
2 - As you were using the same reference to create new buttons, the final array would have the same button in every position.
I moved the initialization of each button inside the for that creates buttons.
var button = UIButton.buttonWithType(UIButtonType.System) as! UIButton
view2.addSubview(button)
3- After that I just updated your constraints to be inserted between the buttons and the scroll view (view2).
And here is the final code:
import UIKit
class ViewController: UIViewController {
let sceneCount = 4
var buttons: [UIButton] = [UIButton]()
func makeLayout(){
//Make the content view
let view1 = UIView()
view1.setTranslatesAutoresizingMaskIntoConstraints(false)
view1.backgroundColor = UIColor.redColor()
//Make the scroll view
let view2 = UIScrollView()
view2.setTranslatesAutoresizingMaskIntoConstraints(false)
view2.backgroundColor = UIColor(red: 0.75, green: 0.75, blue: 0.1, alpha: 1.0)
view.addSubview(view1)
view1.addSubview(view2)
var dictionary = [String: UIView]()
dictionary.updateValue(view1, forKey: "view1")
view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-0-[view1]-0-|", options: NSLayoutFormatOptions(0), metrics: nil, views: dictionary) as [AnyObject])
view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-0-[view1]-0-|", options: NSLayoutFormatOptions(0), metrics: nil, views: dictionary) as [AnyObject])
dictionary = [String: UIView]()
dictionary.updateValue(view2, forKey: "view2")
view1.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-0-[view2]-0-|", options: NSLayoutFormatOptions(0), metrics: nil, views: dictionary) as [AnyObject])
view1.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-0-[view2]-0-|", options: NSLayoutFormatOptions(0), metrics: nil, views: dictionary) as [AnyObject])
//Create the buttons
for i in 0...(sceneCount-1) {
var button = UIButton.buttonWithType(UIButtonType.System) as! UIButton
button.setTranslatesAutoresizingMaskIntoConstraints(false)
button.addTarget(self, action: Selector("scene\(i)Pressed"), forControlEvents: UIControlEvents.TouchUpInside)
button.setBackgroundImage(UIImage(named: "Scene\(i+1)"), forState: UIControlState.Normal)
button.sizeThatFits(CGSizeMake(40, 40))
buttons.append(button)
view2.addSubview(button)
}
//set vertical spacing for all buttons
for i in 0...(sceneCount-1) {
var button1 = buttons[i]
var dictionary2 = [String: UIButton]()
dictionary2.updateValue(button1, forKey: "button1")
view2.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-0-[button1]-0-|", options: NSLayoutFormatOptions(0), metrics: nil, views: dictionary2) as [AnyObject])
}
//set horizontal distance to container for first button
if sceneCount > 0 {
var buttonFirst: UIButton = buttons[0]
var dictionary3 = [String: UIButton]()
dictionary3.updateValue(buttonFirst, forKey: "buttonFirst")
view2.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-[buttonFirst]", options: NSLayoutFormatOptions(0), metrics: nil, views: dictionary3) as [AnyObject])
}
//set horizontal spacing between the buttons
for i in 1...(sceneCount-1) {
var button1 = buttons[i - 1]
var button2 = buttons[i]
var dictionary1 = [String: UIButton]()
dictionary1.updateValue(button1, forKey: "scene1")
dictionary1.updateValue(button2, forKey: "scene2")
view2.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:[scene1]-[scene2]", options: NSLayoutFormatOptions(0), metrics: nil, views: dictionary1) as [AnyObject])
}
//set horizontal distance to container for last button
if sceneCount > 0 {
var buttonLast: UIButton = buttons[sceneCount-1]
var dictionary4 = [String: UIButton]()
dictionary4.updateValue(buttonLast, forKey: "buttonLast")
view2.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:[buttonLast]-|", options: NSLayoutFormatOptions(0), metrics: nil, views: dictionary4) as [AnyObject])
}
}
override func viewDidLoad() {
super.viewDidLoad()
makeLayout()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
How to update the constant height constraint of a UIView programmatically?
Select the height constraint from the Interface builder and take an outlet of it. So, when you want to change the height of the view you can use the below code.
yourHeightConstraintOutlet.constant = someValue
yourView.layoutIfNeeded()
Method updateConstraints()
is an instance method of UIView
. It is helpful when you are setting the constraints programmatically. It updates constraints for the view. For more detail click here.
Programmatically creating constraints bound to view controller margins
Actually the problem in your code is that you did not set the translatesAutoresizingMaskIntoConstraints
of myview
to false
, whenever you want to use auto-layout constraints then you have to set translatesAutoresizingMaskIntoConstraints
of a view to false.
Another Problem is that you do not add myview
on self.view I have updated your code and Its working fine According your constraints.
Put below code in your ViewController .
let myView = UIView()
myView.backgroundColor = UIColor.redColor()
self.view.addSubview(myView)
myView.translatesAutoresizingMaskIntoConstraints = false
view.addConstraint(NSLayoutConstraint(item: myView, attribute: .Top, relatedBy: .Equal, toItem: self.topLayoutGuide, attribute: .Bottom, multiplier: 1, constant: 0))
view.addConstraint(NSLayoutConstraint(item: myView, attribute: .Bottom, relatedBy: .Equal, toItem: self.bottomLayoutGuide, attribute:.Top, multiplier: 1, constant: 20))
view.addConstraint(NSLayoutConstraint(item: myView, attribute: .Width, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute,multiplier: 1, constant: 300))
view.addConstraint(NSLayoutConstraint(item: myView, attribute: .TrailingMargin, relatedBy: .Equal, toItem: view, attribute: .TrailingMargin, multiplier: 1, constant: 0))
Related Topics
Get Attribute of Viewcontroller Created with Storyboard
Xcode/Simulator: How to Run Older iOS Version
Change Bundle Identifier in Xcode When Submitting My First App in iOS
iOS 8.1 Simulator Localization Broken (Nslocalizedstring)
Uiactivityviewcontroller - Email and Twitter Sharing
Why Tesseract Ocr Library (Ios) Cannot Recognize Text at All
No Round Rect Button in Xcode 5
How to Set Fake Gps Location on iOS Real Device
Uiview.Animatewithduration Swift Loop Animation
Calculate Uitableviewcell Height to Fit String
How to Delete an App from Itunesconnect/App Store Connect
Uitableview Disable Swipe to Delete, But Still Have Delete in Edit Mode
Assertion Failure When Using Uisearchdisplaycontroller in Uitableviewcontroller
Afnetworking 2.0 Track File Upload Progress
iOS App Deployment Without Appstore
Open Settings App from Another App Programmatically in Iphone
How to Properly Change My Status Bar Style in Swift 2/ iOS 9