In AutoLayout can you combine both horizontal and vertical constraints using the Visual Format Language?

248 Views Asked by At

In our code in a lot of places, I keep seeing this...

containerView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-0-[view]-0-|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: ["view":childView]))
containerView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-0-[view]-0-|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: ["view":childView]))

It just seems redundant to me. I'm wondering if there's a way to combine the formats into a single string; something like this...

containerView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-0-[view]-0-|;V:|-0-[view]-0-|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: ["view":childView]))

So is something like this possible?

4

There are 4 best solutions below

8
Shehata Gamal On BEST ANSWER

For sorry you can't use this , but you can try something like this

let rr = UIView()

rr.backgroundColor = UIColor.red

self.view.addSubview(rr)

rr.translatesAutoresizingMaskIntoConstraints = false

["H:|-100-[rr]-100-|","V:|-100-[rr]-100-|"].forEach{NSLayoutConstraint.activate(NSLayoutConstraint.constraints(withVisualFormat: $0, options: NSLayoutFormatOptions.init(rawValue: 0), metrics: nil, views: ["rr":rr]))}
3
Rich Tolley On

No, unfortunately the syntax doesn't permit this - see the grammar in the docs

Specifically, the line <orientation> H|V means that the value of orientation can be H or V but not both.

A good alternative for programmatic autolayout is to use an open source DSL library - two popular examples of which are Cartography and Snapkit

I've used both and found them much less fiddly than VFL, and much less verbose than the underlying Apple API

0
vacawama On

Comments:

  1. You should be activating constraints instead of adding them to views (since iOS 8).
  2. You can skip the entire options: NSLayoutFormatOptions(rawValue: 0) since that is the default value.
  3. The VFL returns an array of constraints, so you can just add the arrays together.

With those changes we get this line of code:

NSLayoutConstraint.activate(NSLayoutConstraint.constraints(withVisualFormat: "H:|-0-[view]-0-|", metrics: nil, views: ["view":childView]) + NSLayoutConstraint.constraints(withVisualFormat: "V:|-0-[view]-0-|", metrics: nil, views: ["view":childView]))
0
Cykelero On

Riffing off of Shehata's answer, with different code formatting:

NSLayoutConstraint.activate(
    [
        "H:|-0-[view]-0-|",
        "V:|-0-[view]-0-|"
    ].flatMap {
        NSLayoutConstraint.constraints(
            withVisualFormat: $0,
            metrics: nil,
            views: ["view": gutterView]
        )
    }
)