Where to add Auto Layout constraints code within a custom UIView

17,782

Solution 1

Is it possible to add NSLayoutConstraints within a custom UIView?

Yes it is possible to add constraints within a custom view, organization is very important here, especially if you want to animate parts of your custom view.

Read the subclassing section from Apple's UIView Reference document

Constraints:

requiresConstraintBasedLayout - Implement this class method if your view class requires constraints to work properly.

updateConstraints - Implement this method if your view needs to create custom constraints between your subviews.

alignmentRectForFrame:, frameForAlignmentRect: - Implement these methods to override how your views are aligned to other views.

Where in a UIView is the right place to add them programmatically?

Here is a skeleton outline of a custom class. The key concern is that you centralize your constraints otherwise the class become very messy the more constraints you add. Also you can introduce other settings in the updateConstraints() method and conditionally add or remove constraints by setting your configuration values and then call setNeedsUpdateConstraints().

Any constraints you decide you want to animate should most lightly be instance variables.

Hope this helps :)

class MyCustomView: UIView {

    private var didSetupConstraints = false
    private let myLabel = UILabel(frame: CGRectZero)

    // MARK: Lifecycle
    override init(frame: CGRect) {
        super.init(frame: CGRectZero)
        self.setup()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.setup()
    }


    // Mark: - Setup
    private func setup() {

        // 1. Setup the properties of the view it's self
        self.translatesAutoresizingMaskIntoConstraints = false
        backgroundColor = UIColor.orangeColor()
        clipsToBounds = true

        // 2. Setup your subviews
        setupMyLabel()

        // 3. Inform the contraints engine to update the constraints
        self.setNeedsUpdateConstraints()
    }


    private func setupMyLabel() {

        myLabel.translatesAutoresizingMaskIntoConstraints = false

    }


    override func updateConstraints() {

        if didSetupConstraints == false {
            addConstraintsForMyLabel()
        }

        super.updateConstraints() //Documentation note: Call [super updateConstraints] as the final step in your implementation.
    }

    private func addConstraintsForMyLabel() {

        // Add your constraints here
    }

}

Solution 2

I like to setup my AutoLayout code in the views when it makes more sense. I also found that it is easier to setup all the constraints in one place as part of the init of the customView.

import UIKit

class customView:UIView
{
    var customLabel:UILabel = UILabel()

    override init(frame: CGRect) {
        super.init(frame: frame)
        self.setupUI()
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    func setupUI()
    {
        // Setup UI
        self.customLabel.translatesAutoresizingMaskIntoConstraints = false
        self.addSubview(customLabel)

        // Setup Constraints
        self.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-10-[customLabel]|", options: NSLayoutFormatOptions.init(rawValue: 0), metrics: nil, views: ["customLabel":self.customLabel]))
        self.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-10-[customLabel]-10-|", options: NSLayoutFormatOptions.init(rawValue: 0), metrics: nil, views: ["customLabel":self.customLabel]))
    }
}
Share:
17,782
Bernd
Author by

Bernd

Updated on June 11, 2022

Comments

  • Bernd
    Bernd almost 2 years

    I often see Auto Layout constraints being added in the UIViewController but to me that seems to be the wrong place for layout logic.

    Is it possible to add NSLayoutConstraints within a custom UIView?

    Where in a UIView would be the right place to add them programmatically?

  • victor.vasilica
    victor.vasilica over 7 years
    @Tulleb I believe you forgot to set didSetupConstraints to true if constraints are set in updateConstraints().
  • Tulleb
    Tulleb over 7 years
    Ask @fragilecat instead?
  • victor.vasilica
    victor.vasilica over 7 years
    @fragilecat I believe you forgot to set didSetupConstraints to true if constraints are set in updateConstraints().
  • Peter Hornsby
    Peter Hornsby over 7 years
    No, it has not been forgot, it's a customization point, for a simple view you may only need to setup your constraints once in which case you could set didSetupConstraints to true. However you may have a more complex view that requires you to control the Boolean outside of the updateConstraints method
  • victor.vasilica
    victor.vasilica over 7 years
    @fragilecat understood 👍🏻
  • Vagner
    Vagner about 6 years
    @PeteHornsby you just missed self.addSubview(myLabel) in your setup ;)