Mastering Auto Layout - Part 6: NSLayoutAnchor | Ray Wenderlich Videos

Layout anchors are used for creating constraints on views, in code. They also work on layout guides!


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

At last I got clicking moment “Aha” about using closures in this video because you was writing code in some different way … some kind of code transformations with explanations as non-interrupted flow :blush:
It’s hard for me to explain in english what exactly, because it isn’t my native language, but maybe you know what you’ve changed for this tutorial … and I don’t mean only of using forEach, map, flatMap functions :wink:
So anyway, I want to say Thank You :blush:

1 Like

You’re very welcome! I’m extremely happy to hear that we could help. In terms of this course in particular, Catie and I are very fond of what closures can do for encapsulation.

Hey, Jessy! Maybe I missed something, because I do not fully understand the work of UILayoutGuide.
The piece of code that I really don’t understand is where you identified the imageView’s leading constraint to be equal to spaceGuide’s trailing constraint. The question is: how can UILayoutGuide in this case have a trailing constraint if we did not specify its location? Also: does spaceGuide’s width constraint is changed, when the orientation is rotated and why?
P.S: Sorry for grammar mistakes, English isn’t my native language :slight_smile:
Thank you!!!

how can UILayoutGuide in this case have a trailing constraint if we did not specify its location?

Each of the layout guide has its horizontal position fully-specified like this:

  • The first and last images are constrained to the container guide.
  • All images have their heights and widths set.
  • The spacer guides are constrained between the images.

That’s enough info for Auto Layout to know where to place their X values!

does spaceGuide’s width constraint is changed, when the orientation is rotated

The constraint doesn’t change, but the width itself can change!

and why?

Rotation is one of the “External Changes” that can occur which will cause Auto Layout to recalculate your views’ frames.

1 Like

thank you very much for your answer!!

I feel this lesson is unnecessarily complicated with all these nested code. If someone come here to learn AutoLayout, it’ll be a bummer for them because they couldn’t understand the codebase. I’d say writing more lines of readable code is much better than writing complicated non-beginner friendly code which is just 20 lines. Especially when it comes to tutorials like this.

1 Like

Thank you for the feedback!

This kind of thing is very subjective; I wrote it the way I’d like to read it. If you could post an example of how you’d do it instead, that would be helpful to me, and possibly to other viewers!

Best lesson of all iOS Path. Thanks Jessy!

1 Like

@andremvb Really glad you like it! :]

Here is a verbose version of what was shown in the video.
Replace the NSLayoutConstraint.activate() call with:

    // center container guide on x axis
containerGuide.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
// Setting maximum width to safeAreaLayoutGuide's left and right edges - but can be narrower
containerGuide.leadingAnchor.constraint(greaterThanOrEqualTo: view.safeAreaLayoutGuide.leadingAnchor).isActive = true
containerGuide.trailingAnchor.constraint(lessThanOrEqualTo: view.safeAreaLayoutGuide.trailingAnchor).isActive = true

// get first spacerGuide constraint
let constraint = spacerGuides.first!.widthAnchor.constraint(equalToConstant: 80)
// set priority on that constraint
constraint.priority = UILayoutPriority(749)
// commit the constraint to the layout
constraint.isActive = true

// set last spacerGuide width to equal first spacerGuide width
spacerGuides.last!.widthAnchor.constraint(equalTo: spacerGuides.first!.widthAnchor).isActive = true

// Loop through the imageViews array
for (index, imageView) in imageViews.enumerated() {
  // center each imageView on the Y axis with the centerYAnchor of the root view
  imageView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
  // height and width should be the same (square). These values are 'intrinsic'?
  imageView.heightAnchor.constraint(equalTo: imageView.widthAnchor).isActive = true
  // if this is the first imageView in the array, the leading edge should match the leading edge of the container view. If not, the leading edge should meet the trailing edge of the spacerGuide which comes before it.
  if index == 0 {
    imageView.leadingAnchor.constraint(equalTo: containerGuide.leadingAnchor).isActive = true
  } else {
    imageView.leadingAnchor.constraint(equalTo: spacerGuides[index - 1].trailingAnchor).isActive = true
  }
  // if this is the last imageView in the array, the trailing edge should match the trailing edge of the continer view. If not, the trailing edge should match the leading edge of the spacerGuide which comes after it.
  if index == imageViews.count - 1 {
    imageView.trailingAnchor.constraint(equalTo: containerGuide.trailingAnchor).isActive = true
  } else {
    imageView.trailingAnchor.constraint(equalTo: spacerGuides[index].leadingAnchor).isActive = true
  }
  
  // for each imageView following the first one, make it so its width is equal to the first imageView's width.
  if index != 0 {
    imageView.widthAnchor.constraint(equalTo: imageViews.first!.widthAnchor).isActive = true
  }
}

@chuck_taylor Thank you for sharing your solution - much appreciated! :]

I agree. I’m still trying to work through the original code and the verbose version Chuck Taylor provides (thank you!), and here I thought I had a good understanding of closures. Hopefully it will click for me like it did for “ilmaros.” But this has certainly stopped my study of auto layout dead in its tracks for the time being.

I couldn’t compile the code because I get the error message that the compiler cannot check the type-expression of the NSLayoutConstraints.activate(…). It asks me to try to break-up expressions.

1 Like

Since we recorded this course, there are many cases where the compiler has newly required adding return types to closure signatures, where implicit typing used to work.

In this case, all you need to do is add -> [NSLayoutConstraint] to this line:

+ imageViews.enumerated().flatMap { index, imageView -> [NSLayoutConstraint] in
1 Like

Hi I had followed the tutorial and when I tried to build or run my app I got this error :

The compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions

I had the same problem with the compiler message. The fix two lines above sorted it.

@charlybarron Do you still have issues with this?

Hi ! I have a question ! Why leading Anchor of the container is greaterThanOrEqualTo but the trailing Anchor is lessThanOrEqualTo ?

Have you tried other combinations? They’ll all work. This one just keeps the container view inside the view!