“Width equals height” constraint using visual format language

1.4k Views Asked by At

In order to add width equals to its superview height we can do following

NSLayoutConstraint(item: view, attribute: .width, relatedBy: .equal, toItem: view.superview, attribute: .height, multiplier: 1, constant: 0)

or we can do it from interface builder

enter image description here

But how can I do the same using VFL?

3

There are 3 best solutions below

0
On

I don't think you can, since that's a pretty uncommon setup. Esoteric use cases like this are where it's best to use the explicit initializer on NSLayoutConstraint.

0
On

From the documentation of Auto Layout Guide: Visual Format Language

The notation prefers good visualization over completeness of expressibility. Most of the constraints that are useful in real user interfaces can be expressed using visual format syntax, but there are a few that cannot. One useful constraint that cannot be expressed is a fixed aspect ratio (for example, imageView.width = 2 * imageView.height). To create such a constraint, you must use constraintWithItem:attribute:relatedBy:toItem:attribute:multiplier:constant:.

"Width equals Height" is a ratio (to 1). So it's not possible.

0
On

As already mentioned, the Docs point out that you cannot set certain (common) constraints using VFL. Here's a simple example of adding just one additional line to get what you want.

You can run this in a Playground:

import UIKit
import PlaygroundSupport


class TestVC: UIViewController {

    let squareView: UIView = {
        let v = UIView()
        v.translatesAutoresizingMaskIntoConstraints = false
        v.backgroundColor = .green
        return v
    }()

    override func viewDidLoad() {
        super.viewDidLoad()

        view.backgroundColor = .yellow

        // add the subview
        view.addSubview(squareView)

        //Views to add constraints to
        let views = Dictionary(dictionaryLiteral: ("sqV", squareView))

        // 40 points from left, width of 100
        let horizontalConstraints = NSLayoutConstraint.constraints(withVisualFormat: "H:|-40-[sqV(==100)]", options: [], metrics: nil, views: views)
        view.addConstraints(horizontalConstraints)

        // 40 points from top, no height setting
        let verticalConstraints = NSLayoutConstraint.constraints(withVisualFormat: "V:|-40-[sqV]", options: [], metrics: nil, views: views)
        view.addConstraints(verticalConstraints)

        // set height equal to width (1:1 ratio)
        squareView.heightAnchor.constraint(equalTo: squareView.widthAnchor, multiplier: 1.0).isActive = true

    }

}

let vc = TestVC()
PlaygroundPage.current.liveView = vc