Programmatic Auto Layout (Part 1)

So I know all about Auto Layout now - the use of constraints, content hugging, distribution....various things in the previous course! This next - and last - Treehouse course is titled 'Programmatic Auto Layout'. I assume from this that there is an element of coding to sorting out some of the layout of different views. We shall see!

Why Write Code?

So yes - this is what the course is exactly about! But why use code over interface builder?


1. Some developers prefer code - faster and they do not like using graphics etc.
2. IB and code do not always work so well together. Conflicts occurring etc.
3. Third party libraries - not sure about this yet.

Apple have created newer APIs, to make it easier to use in code.

NSLayoutConstraint...

override func viewWillLayoutSubviews() {
        super.viewWillLayoutSubviews()
        
        redView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(redView)
        
        let horizontalCenterConstraint = NSLayoutConstraint(item: redView, attribute: .centerX, relatedBy: .equal, toItem: view, attribute: .centerX, multiplier: 1.0, constant: 0)
        
        NSLayoutConstraint.activate([
            horizontalCenterConstraint
        ])
    }

}

So this is code that Pasan has already typed. When constraints are generated this way, any constraints shown implicitly will be at conflict with the ones in code. 

redView.translatesAutoresizingMaskIntoConstraints = false

This line removes that factor. 

let horizontalCenterConstraint = NSLayoutConstraint(item: redView, attribute: .centerX, relatedBy: .equal, toItem: view, attribute: .centerX, multiplier: 1.0, constant: 0)

These are all attributes of the NSLayoutConstraint. All of that is very wordy for just one constraint!
I can't see why I would ever do this over using the Auto Layout features.

NSLayoutConstraint.activate([
            horizontalCenterConstraint
        ])

NSLayoutConstraints Instances

      let redViewWidthConstraint = NSLayoutConstraint(item: redView, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 200)
        let redViewHeightAttribute = NSLayoutConstraint(item: redView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 100)

Here are two more constraints added - not actually that complex!







Ok, so all of this is pretty confusing - even with the diagrams. Basically, the position of the object - the orange dot - shows the x and y range from it. It can be either direction and the negative/positive increase is shown (no decrease as such). 

The Y axis increases as you go down - interesting and different to coordinates!

Layout Anchors

Understandably, the code is so verbose that it makes you want to use AL instead! Apparently, Xcode recognised this and created an NSAnchor class. This is supposed to be much more fluid. 

 NSLayoutConstraint.activate([
            redView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            redView.widthAnchor.constraint(equalToConstant: 200.0),
            redView.heightAnchor.constraint(equalToConstant: 100.0),
            redView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -50.0)
            
        ])

OK so the anchor APIs make it a lot easier! This code is a lot more concise. 

NSLayout Anchor are basically very useful. They are all part of the NSLayout constraint but is a far easier way of writing the actual code. 

Visual Format Language

Using text based visual strings is another way of creating layout code. 

class VisualFormatExampleController: UIViewController {
    
    let redView = UIView()
    let greenView = UIView()
    let blueView = UIView()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        redView.backgroundColor = .red
        greenView.backgroundColor = .green
        blueView.backgroundColor = .blue
    }


So loading the VisualFormatExampleController starts it off. 

  override func viewWillLayoutSubviews() {
        super.viewWillLayoutSubviews()
        
        redView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(redView)
        
        greenView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(greenView)
        
        blueView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(blueView)


So this bit here means that the autoresizing does not happen automatically? Unclear. 

let views: [String: Any] = [
            "redView": redView,
            "greenView": greenView,
            "blueView": blueView,
        ]

So the point of this is to create several constraints at once. 

NSLayoutConstraint.constraints(withVisualFormat: "H:[redView(200)]", options: [], metrics: metrics, views: views).map { $0.isActive = true }

This is - admittedly from Pasan - that there is a lot of 'magic' going on. The H bit means that there is a horizontal string being used. The redView indicates that it is that view with a width constraint of 200. 


I've switched off for the last part of this - far too confusing! This workshop is definitely more complex than the last. I'm still struggling to see the purpose of using all of this code when you have auto layout. However, like Pasan has stated, some developers work only with code, so it's good to know what's going on! Hopefully in the next set of videos it will explain what is going on a bit more clearly. That should be the last Treehouse one - for now at least!



Comments

Popular posts from this blog

*Xcode Project Entry 2* F1 Quiz - part 1

Angela Yu Course Part 10 (up to lesson 112)

Angela Yu Xcode 12 Course - Part 7 (lectures 74 to 79)