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
You've learned much about using constraints in Interface Builder, now see how to interact with them in your code.
Hi, thanks so much for the great video series!
A few quick questions:
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â?
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?
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.
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.
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!
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?
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.
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.