Reputation: 4045
I'm trying to define constraints in AutoLayout which would automatically resize a view when another one changes.
There are two views side by side and I would like for the right one to grow only by simply making the left one thinner (and not directly changing the right-side-view's width constraint). I'm asking whether this can be done with clever use of constraints.
The change need not be animated.
This is all the code in the app:
class ViewController: UIViewController {
var view1 = UIView()
var view2 = UIView()
var h1Constraints: [AnyObject]?
var h2Constraints: [AnyObject]?
var v1Constraints: [AnyObject]?
var v2Constraints: [AnyObject]?
override func viewDidLoad() {
super.viewDidLoad()
// Boilerplate
view1.backgroundColor = UIColor.redColor()
view2.backgroundColor = UIColor.greenColor()
view2.addGestureRecognizer(UITapGestureRecognizer(target: self, action: "grow"))
view1.setTranslatesAutoresizingMaskIntoConstraints(false)
view2.setTranslatesAutoresizingMaskIntoConstraints(false)
view.addSubview(view1)
view.addSubview(view2)
// Constraints
let views = ["view1":view1, "view2": view2]
let metrics = ["halfScreenWidth":view.frame.size.width/2, "screenHeight":view.frame.size.height]
h1Constraints = NSLayoutConstraint.constraintsWithVisualFormat("H:|[view1(>=halfScreenWidth)]->=0-|", options: NSLayoutFormatOptions(0), metrics: metrics, views: views)
h2Constraints = NSLayoutConstraint.constraintsWithVisualFormat("H:|->=0-[view2(>=halfScreenWidth)]|", options: NSLayoutFormatOptions(0), metrics: metrics, views: views)
v1Constraints = NSLayoutConstraint.constraintsWithVisualFormat("V:|[view1(screenHeight)]", options: NSLayoutFormatOptions(0), metrics: metrics, views: views)
v2Constraints = NSLayoutConstraint.constraintsWithVisualFormat("V:|[view2(screenHeight)]", options: NSLayoutFormatOptions(0), metrics: metrics, views: views)
view.addConstraints(h1Constraints!)
view.addConstraints(h2Constraints!)
view.addConstraints(v1Constraints!)
view.addConstraints(v2Constraints!)
}
@objc func grow() {
for var index = 0; index < h1Constraints?.count; ++index {
var constraint = h1Constraints![index] as! NSLayoutConstraint
if constraint.firstAttribute == .Width {
constraint.constant = 20
}
}
self.view.layoutIfNeeded()
}
}
I'm simply trying to tell the layout engine that the views are both greater than, or equal to half of the screen width, while having an adjustable margin (greater than, or equal to 0).
This way, when I change the left-side-view's width to 20, I thought that the right-side-view would grow, since it has a >= width declared.
This does not work. While the left side shrinks, the right side stays the way it is.
Can that sort of relation be achieved with Auto Layout?
EDIT:
As per @luk2302 's answer, the solution was the following:
// Constraints
let views = ["view1":view1, "view2": view2]
let metrics = ["halfScreenWidth":view.frame.size.width/2, "screenHeight":view.frame.size.height]
h1Constraints = NSLayoutConstraint.constraintsWithVisualFormat("H:|[view1(>=halfScreenWidth)][view2(>=halfScreenWidth)]|", options: NSLayoutFormatOptions(0), metrics: metrics, views: views)
v1Constraints = NSLayoutConstraint.constraintsWithVisualFormat("V:|[view1(screenHeight)]", options: NSLayoutFormatOptions(0), metrics: metrics, views: views)
v2Constraints = NSLayoutConstraint.constraintsWithVisualFormat("V:|[view2(screenHeight)]", options: NSLayoutFormatOptions(0), metrics: metrics, views: views)
view.addConstraints(h1Constraints!)
view.addConstraints(v1Constraints!)
view.addConstraints(v2Constraints!)
Upvotes: 0
Views: 93
Reputation: 57114
Yes it can be achieved if I understand your requirement correctly. I recommend the following constraints:
Then you can change the constant value of the last constraint and everything should behave as desired.
Note that I have never tried creating constraints by code, only using the IB - but this would be the way I would do it there.
Upvotes: 2