Zoltán Matók
Zoltán Matók

Reputation: 4045

Automatically adjust view width when other views' constraints change

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.

This is what happens, but shouldn't

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

Answers (1)

luk2302
luk2302

Reputation: 57114

Yes it can be achieved if I understand your requirement correctly. I recommend the following constraints:

  • align the left of the left view to the left of the screen/superview
  • align the right of the right view to the right of the screen/superview
  • align the right of the left view with the left of the right view.
  • add a constraint for the width of the left view

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

Related Questions