This workshop will be retired on May 31, 2020.
NSLayoutConstraint Instances9:27 with Pasan Premaratne
In code constraints are represented by the NSLayoutConstraint class. In this video let's look at how we can build a layout in the most basic way - using the NSLayoutConstraint initializer
In the previous video, 0:00 we added a centerXConstraint from the redView to the rootView. 0:02 A frame doesn't work with just a centerX coordinate, it also needs an origin. 0:06 To determine the origin from a centerX attribute, we also need to define a width. 0:11 This way, the system can have that width and 0:16 determine the x origin by subtracting half the width from the centerX attribute. 0:19 Let's try and sort out the origin's x coordinate and 0:24 the width simultaneously by adding an a widthConstraint. 0:27 When we did this in Interface Builder, 0:31 this was immediately obvious because we get color coded eye bars 0:33 to indicate whether our layout has been satisfied or not. 0:37 With layout code, however, until you run the app 0:41 you don't really have any indication as to the state of your layout. 0:44 If your layout is broken, you'll get an output in the console area, but for 0:48 this series of videos we're going to focus on how we can build layouts rather than 0:52 debug them. 0:56 That will be a future series. 0:57 Okay, so for the widthConstraint let's do the same thing. 0:59 We'll create a constraint using the Initializer, assign it to a constant, 1:03 and then activate it. 1:07 So let redViewWidthConstraint = NSLayoutConstraint. 1:08 The item is the red view. 1:16 The attribute is .width, relatedBy .=. 1:20 Now the interesting thing here, 1:26 in contrast to the previous centerXConstraint, 1:28 is that a widthConstraint isn't a relationship between two views. 1:31 Because a widthConstraint only operates on one view, 1:36 the second part of the constraint equation is a bit different. 1:40 So here, for the two item, we're gonna say nil, for the attribute, 1:44 we'll say notAnAttribute. 1:48 The multiplier is 1.0, and the constant is 200. 1:51 So like before, the first item is still the redView, the attribute is width, and 1:56 the relationship is still equal, all familiar stuff. 2:00 The two item here doesn't really matter. 2:04 So the way we indicate this is by specifying nil for 2:06 the item and not an attribute for the attribute. 2:09 This is essentially what auto layout does under the hood when we add height or 2:13 width constraints. 2:17 And with that we have our widthConstraint, and 2:19 we can activate it by adding it to the array we defined earlier. 2:21 So down here we'll add a comma, and we'll say redViewWithConstraint. 2:25 We've now provided enough information in the horizontal direction. 2:31 Let's switch over to the vertical direction, and 2:35 we'll start with a heightConstraint. 2:37 A heightConstraint is nearly identical to the widthConstraint we just created, 2:39 the only difference being the height attribute is specify instead of the width. 2:44 So we'll say let redViewHeightAttribute = NSLayoutConstraint. 2:48 So again her the item is the redView, the attribute this time is height so .height. 2:56 This is an equal relationship, no second item, so nil, notAnAttribute and 3:01 then multiplier is 1.0 with a constant value of 100 points. 3:07 Okay, so let's add this to our array of constraints as well. 3:12 redViewHeight, oops, I called this heightAttribute, 3:15 let me command click here and select rename and we'ell call 3:20 this redViewHeightConstraint, okay. 3:25 We're almost there, so our view has a height and a width, so 3:30 the system can size it appropriately. 3:33 It can determine the x origin because we've specified that it should always be 3:36 centered. 3:39 But because it cannot determine the y origin, 3:41 it defaults to giving a y coordinate of zero. 3:43 Let's add one final constraint to satisfy the system. 3:46 Let's pin the view 50 points from the bottom of the screen. 3:50 So how will that satisfy the layout requirements? 3:53 Well, we already know the x value for the origin and we have a height value. 3:55 The systems knows what the y value is for the bottom of the screen. 4:00 By subtracting 50 points from the y coordinates of the bottom edge of 4:03 the containing view, and then subtracting the height of the view from that, 4:06 we now have a y coordinate for the origin. 4:11 So at this point we have the origin and 4:13 size information needed for auto layout to position the view. 4:15 Defining this constraint is no different than any of the others we've done, so 4:19 we'll call this redViewBottomSpaceConstraint. 4:23 And again we'll use that Initializer. 4:30 The first item is a redView. 4:33 And since this going from the bottom of the redView, we'll say .bottom. 4:35 There's an equal relation as well. 4:40 Now the second item here is the root view, and 4:41 the attribute is again the bottom, so we'll say .bottom. 4:46 Now at this point, before I continue, 4:52 you might notice that you learnt about safe area layout guides in iOS 11, and 4:54 then prior to that about top and bottom layout guides. 4:58 And what we really should be doing is pinning to either the safe area layout 5:01 guide, which would do by saying view dot safe area dot layout guide .bottom or 5:06 by pinning to the actual view controllers layout guides in versions prior to iOS 11. 5:10 Or we're going to gloss over that, we'll come back to it. 5:15 Okay, the attribute is bottom so far, the multiplier is 1.0, and the constant, since 5:19 we want to space this 50 points above the bottom of the root view is going to be 50. 5:25 Let's add this final constraint to our array, 5:31 redViewBottomSpaceConstraint, and let's run the app. 5:34 We actually didn't need to do one thing, because when it appears you won't see and 5:44 that's because our view does not have a background color. 5:49 So in viewDidLoad, we'll say redView.backgroundColor = .red. 5:52 All right, let's give that a try. 5:55 Now when the Simulator loads, 6:02 you'll see that this scene does not match our expectations. 6:04 The reason for this is the constant value we specified for the last constraint. 6:08 When defining spacing constraints and interface builder using the pin menu, 6:13 we don't have to worry about indicating whether we are pinning a review above or 6:17 below another because they are laid out in a scene with drag and drop views and 6:22 Interface Builder can figure that out. 6:27 Whether a view is pinned above or below does matter though. 6:29 And in encode, the way we indicate this is by using positive or 6:33 negative values for the constant to indicate direction. 6:36 Coordinates in iOS are represented on a grid 6:41 that has its origin in the top left corner. 6:44 X values increase to the right horizontally, Y values increase downwards. 6:47 If you have an object, let's call it A, that's set in any random point, 6:52 a second object B placed to the left of A has smaller 6:57 X-axis values since the values increase to the right. 7:01 If we wanted to define the X value of B in relation to A, we would take the X 7:06 value of A and simply deduct the amount of space between the two. 7:11 Since we're deducting, this means we're using a negative number. 7:15 Now if B was to the right of A, the X value of B would be A's X value plus 7:19 whatever the space is, since X axis values increase to the right. 7:24 Objects placed to the left of the reference object use negative space values 7:30 to define their X origins, while objects placed to the right use positive values. 7:34 This applies to the vertical direction as well. 7:41 Since values increase downwards, if B was below A, 7:43 then we would use a positive space value to indicate where B's Y origin would lie. 7:47 But if B was above, we would use a negative value. 7:53 Back to the issue at hand, we use a positive value in combination with 7:57 a bottom space constraint which is a constraint in the vertical orientation. 8:00 Since the Y axis increases as you go down, the system has placed the bottom 8:05 of the red view 50 points below the bottom of the root view, 8:10 since we used a positive constant value. 8:13 So to correct this, we just need to go back to our BottomSpaceConstraint. 8:16 And for the constant we make it a negative value. 8:20 This tells the system to place the bottom of the redView 50 points 8:23 above the bottom of the root view. 8:27 And if we stop and hit Run, we should have our final layout. 8:29 As I mentioned earlier, there is one thing I glossed over that's quite important and 8:35 worth pointing out. 8:39 We've pinned the bottom of the redView to the bottom of the root view. 8:41 But when we learned about constraints and how to define them in Interface Builder, 8:44 we also learned about an introduction of safe areas in iOS 11 and 8:48 how to position content so it's not obscured by system elements. 8:52 Don't worry, we'll revisit this topic in a bit. 8:57 Before we get in some practice with writing auto layout code, 9:00 let's look at one more topic. 9:03 NSLayoutConstraints Intializers, the ones we used here, are not the best way to 9:05 write layout code since it's quite verbose and involves quite a bit of repetition. 9:10 In iOS 9, Apple introduce the NSLayoutAnchor class 9:16 in a set of APIs that make writing a layout code much easier. 9:21 Let's check it out in the next video. 9:24
You need to sign up for Treehouse in order to download course files.Sign up