Mastering Auto Layout - Part 4: Constraints in Code | Ray Wenderlich

You've learned much about using constraints in Interface Builder, now see how to interact with them in your code.


This is a companion discussion topic for the original entry at https://www.raywenderlich.com/3933-mastering-auto-layout/lessons/4

Hi, thanks so much for the great video series!

A few quick questions:

  1. At the end of the setupImageConstraints(size: ) function, why are the containerGuide constraints set to be >= and <= instead of just = (equalTo) the leading and trailing anchors of ‘view’?

  2. Also related to containerGuide constraints, I noticed that we didn’t use any constraint for the Y axis (e.g., centerYAnchor). Would this be necessary if we had more y-axis positioning/centering tasks to do?

  1. What we want here is for the images to be a fixed spacing apart, centered horizontally, but never running off the edges of the view. Because the first and last images are constrained to the leading and trailing edge of the guide, if we made the guide equal to the view, the images would always be at the leading and trailing edges of the view, with the spacing being variable, instead of fixed. That’s not necessarily bad, if that’s what the design calls for, it’s just not what we want in this case.

  2. Guides are the exception to the rule that everything must be fully constrained. Because they are non-visual, you can use them in only the dimension that you need them and leave constraints off for everything else. In this case, you could constrain the images to the guide, in the Y direction, and then the guide to the view, but the same thing is accomplished by setting the center Y of each image to the center Y of the view. This is a good example of the fact that there are often several ways to accomplish the same thing in auto layout, and one isn’t always better than the other. If you thought it was likely in the future for this design to change where the whole group would move in the vertical direction, it would be better to change one constraint (for the group) than one for each image. In that case, your way would be better.

Good questions!

It’s worth noting that in the demo project reinstalling constraints when rotations are occurred isn’t necessary.

Yeah, that seems to be right. I’m not sure why that’s in there, but I think in an earlier version of the code, it was doing some size-dependent calcs that aren’t in there anymore. Not until video 9 do we do something different with the size.

Thanks for pointing it out.

Is it considered ok to do some layout in IB and some in code? I can think of cases where it would be easier to do some layout in code rather than death by 1000 clicks trying to create it in IB, however I can also see where having layout in two places would get troublesome to keep up with. In Xcode, does preview show the layout from both IB and from code?

Great course!

Absolutely! It’s often easiest to setup your layout in IB that handles the majority of your cases and then add some code to tweak for specific situations. Preview will NOT show the layout from code with one exception: if you create a custom view and make it IBDesignable, IB will run your code to determine how to display your custom view.

1 Like

You’d rather type 1000 lines of code?

Very cool tutorial! A little over my head but made more sense after I could step back and digest each section of code. I can definitely see the advantages of combining both techniques. After years of doing layout in PS and Illustrator , IB is very comfortable and accommodating.

Now onto the challenge!

I think I’ll stick with the combo approach, much easier for my brain to absorb too! :wink:

Onto the next!

In both the demo and the challenge we only set the aspect ratio of the UIImageViews instead of explicitly setting their height/width to constants.

By doing this, do we allow auto layout to compress or expand their intrinsic content size depending on the view bounds and the sum of their constraints?

Well, first, don’t think of intrinsic content size as expanding or contracting. If the content doesn’t change, the intrinsic content size doesn’t change. The size used in layout might change, but the intrinsic size is the size the content “wants” to be.

The reason for setting the aspect ratio constraints is to keep the images square, but it does connect the vertical and horizontal layouts. If a different constraint causes the images to be compacted horizontally, the aspect ratio constraint will cause the height to reduce as well. And if there were other constraints between other views and the images in the vertical direction, they would be impacted also.

I almost never explicitly set height and width constraints. In this case, I want the images to be as close to their intrinsic size as they can get, which is accomplished by the built-in intrinsic content size constraints. But I also want to enforce other constraints, like the spacing between the weather icons and the spacing between them and the edges of the screen.

Does that help?

1 Like

Thanks! That clarifies it.

Hi Jerry,

Thanks for excellent tutorial.

Unless I missed it, did you discuss why using a UIStackView would not be a better option to do the layout and spacing. Isn’t it the more preferred method rather than using layout guides?

Thanks

Stack view is definitely one of the first tools I use for layout. There are definitely situations where it falls short or you have to use constraints in addition to stack view.

Hello, was looking for an answer, but starting to give up or need to have a good night of sleep.

Can anyone with experience tell me how to set this constraint programmatically? The issue I have is that I can’t set multiplier. From interface builder, it works perfectly.

Screenshot 2020-02-21 at 02.16.16

So, after sleep, finally, everything comes to place.

    //fingerView.topAnchor.constraint(equalTo: wheelView.topAnchor, constant: 20).isActive = true

fingerView.heightAnchor.constraint(equalTo: fingerView.widthAnchor, multiplier: 8.0 / 7.0).isActive = true

    fingerView.centerXAnchor.constraint(equalTo: wheelView.centerXAnchor).isActive = true

    fingerView.widthAnchor.constraint(equalTo: wheelView.widthAnchor, multiplier: 0.141876).isActive = true
    
    NSLayoutConstraint(item: fingerView,
                       attribute: NSLayoutConstraint.Attribute.top,
                       relatedBy: NSLayoutConstraint.Relation.equal,
                       toItem: wheelView,
                       attribute: NSLayoutConstraint.Attribute.top,
                       multiplier: 1.4,
                       constant: 0).isActive = true

The problem was I was mixing constraint styles in a bad way. Was adding the last constraint like this fingerView.addConstraint(topConstraint) and had instead just made it isActive = true.

@vidocaz Glad you sorted it out! Cheers! :]

1 Like