Jordan H
Jordan H

Reputation: 55665

Set up NSLayoutConstraint constant based on a view's height or screen height

I have programmatically created an auto layout constraint that moves a label up 25 points from the bottom of its parent view. There are no other constraints I define on this scene. 25 is fine on most devices, but it's too far up on the iPhone 4s. I would like to make it about 15 up from the bottom for that screen size. But then I was thinking it would be much better to obtain a variable constant instead of enforcing a fixed value for all screen sizes, or attempting to change it for one specific screen size. But it doesn't seem this is possible with Auto Layout. Is it?

I was thinking one way to obtain a variable constant would be to calculate a value based on the screen (or view) height. For example, the constant would be equal to self.view.frame.size.height / 30. On iPhone 4 (portrait only) it would be 16, iPhone 5 it would be almost 19, etc. This would be perfect. Or another way, 3% of the height. These values would need to be dynamic for rotations though, as the height will change.

Is it possible to use auto layout constraints that have variable constants based on some calculation or screen/view height? Or is there some other solution that will allow me to obtain the desired behavior - avoiding fixed auto layout constants?

Here's some example code, from viewDidLoad:

let footerLabel = UILabel()
footerLabel.text = "my text"
footerLabel.sizeToFit()
footerLabel.setTranslatesAutoresizingMaskIntoConstraints(false)
self.view.addSubview(footerLabel)
self.view.addConstraint(NSLayoutConstraint(item: footerLabel, attribute: .Bottom, relatedBy: .Equal, toItem: self.view, attribute: .Bottom, multiplier: 1, constant: -25))
self.view.addConstraint(NSLayoutConstraint(item: footerLabel, attribute: .CenterX, relatedBy: .Equal, toItem: self.view, attribute: .CenterX, multiplier: 1, constant: 0))

Upvotes: 2

Views: 4148

Answers (3)

Judson Douglas
Judson Douglas

Reputation: 331

I was thinking one way to obtain a variable constant would be to calculate a value based on the screen (or view) height. For example, the constant would be equal to self.view.frame.size.height / 30. On iPhone 4 (portrait only) it would be 16, iPhone 5 it would be almost 19, etc. This would be perfect. Or another way, 3% of the height. These values would need to be dynamic for rotations though, as the height will change.

You can just change your first constraint to:

self.view.addConstraint(NSLayoutConstraint(item: footerLabel, attribute: .Bottom, relatedBy: .Equal, toItem: self.view, attribute: .Bottom, multiplier: 0.97, constant: 1))

Keeping the constant 0 and changing the multiplier to 0.97 means the bottom of your label will always be 3% higher than the bottom of your view.

Upvotes: 1

Khaled Barazi
Khaled Barazi

Reputation: 8741

I would not assign the constraint directly to the view.

I would:

  1. Create a variable property for your NSLayoutConstraint
  2. In viewDidLoad, use this function to initialize it:

    • (instancetype)constraintWithItem:(id)view1 attribute:(NSLayoutAttribute)attr1 relatedBy:(NSLayoutRelation)relation toItem:(id)view2 attribute:(NSLayoutAttribute)attr2 multiplier:(CGFloat)multiplier constant:(CGFloat)c
  3. Add the constraint to the view using self.view.addConstraint

  4. Assign different values (using .constant) to that constraint when orientation changes or based on device.

Upvotes: 0

rintaro
rintaro

Reputation: 51911

You can setup "spacer" view with which height are constrained to 3% of the view.

override func viewDidLoad() {
    super.viewDidLoad()

    let label = UILabel()
    let spacer = UIView()

    label.setTranslatesAutoresizingMaskIntoConstraints(false)
    spacer.setTranslatesAutoresizingMaskIntoConstraints(false)
    spacer.hidden = true

    view.addSubview(spacer)
    view.addSubview(label)
    var views = ["spacer":spacer, "label":label]
    view.addConstraint(NSLayoutConstraint(item: spacer, attribute: .Height, relatedBy: .Equal, toItem: view, attribute: .Height, multiplier: 0.03, constant: 0))
    view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:[label][spacer]|", options: nil, metrics: nil, views: views))

    view.addConstraint(NSLayoutConstraint(item: label, attribute: .CenterX, relatedBy: .Equal, toItem: view, attribute: .CenterX, multiplier: 1, constant: 0))

    label.backgroundColor = UIColor.purpleColor()
    label.text = "THIS IS MY LABEL"
}

Upvotes: 1

Related Questions