Tutorial: iOS 6 Auto Layout versus Springs and Struts – Part 3 of 3

This tutorial is an excerpt from our book series iOS App Development for Non-Programmers, available in the iBookStore for the iPad, and on Amazon.


Part 1 discusses the two layout options, then dives in on springs and struts. Part 2 discusses the new Auto Layout option available in iOS 6 and later. Part 3 takes tutorial on Auto Layout to the next level!


Setting Constraints on Multiple Controls


Now that you have a basic understanding of how to set constraints on a single control, it’s time to learn how to set constraints on multiple controls in relation to the parent view and each other.


If you haven’t already downloaded the sample code for part 1 and part 2 of this tutorial, click on the following link:


Tutorial Samples


  1. If it’s not already open, in Xcode, open the AutolayoutDemo project. 

  2. If it’s not already selected, go to the Project Navigator and select the MainStoryboard file.

  3. Drag an Image View from the Object Library and position it on the left side of the scene directly below the label. When the guide lines appear as shown in Figure 8.43, let go of the mouse button to drop the label in place.

    Figure 8.43 Drop an image view on the scene.

    This adds four constraints to the scene, which you can see in the scene itself as well as the Size Inspector as shown in Figure 8.44:

    • Width Equals: 240

    • Height Equals: 128

    • Top Space to Label – Oliver! Equals: Default

    • Leading Space to: Superview Equals: Default

  4. Figure 8.44 Four constraints are created for the image view.

    The width and height constraints are getting added because there is no default guide line against which the right and bottom sides of the image view can be placed. This is perfectly acceptable.

    The top and left sides of the image view are positioned against guide lines, so their spacing is set to Default.

  5. Let’s resize the image view so we have room to place a text view next to it. 
  6. Go to the Size Inspector (second button from the right in the Inspector toolbar) and change the Width to 150 and the Height to 150.

    When you do this, it changes the width and height constraints to the new values.

  7. Now let’s put an image in the image view. With the image view still selected, go to the Attributes Inspector (third button from the right in the Inspector toolbar) and set its Image attribute to OliverCast.png. This displays the image in the image view as shown in Figure 8.45.
  8. Figure 8.45 The image is set in the image view.

  9. Next, drag a Text View control from the Object Library and position it on the right side of the scene directly below the label. When the guide lines appear as shown in Figure 8.46, let go of the mouse button to drop the text view in place.

    Figure 8.46 Drop a text view on the scene.

    This adds the four constraints shown in Figure 8.47:

    • Height Equals: 128

    • Width Equals: 240

    • Trailing Space to: Superview Equals: Default

    • Top Space to: Label – Oliver! Equals: Default

    Figure 8.47 Four constraints are created for the text view.

  10. We can get rid of the hard-coded height constraint by aligning the bottom of the text view with the image view. 
  11. To do this, grab the resizing handle at the bottom of the text view and drag it downward. When the guide line appears (

    Figure 8.48 Align the bottom of the text view with the bottom of the image view.

    Doing this removes the hard-coded height constraint and replaces it with a new Align Bottom to: Image View – OliverCast.png constraint.

  12. Let’s align the left edge of the text view right up against the right side of the image view. To do this, grab the resizing handle on the left side of the text view and drag it to the right (Figure 8.49). When the width of the text view is 130.0 points as shown in the width/height popup, then release the mouse.
  13. Figure 8.49 Adjust the width of the text view.

  14. Now let’s put some meaningful text in the text view by hooking it up to an outlet. To do this, first go to the Xcode toolbar at the top of the screen and click the center button in the Editor button group. This should automatically display the ViewController.h file in the Assistant Editor.
  15. Next, hold the Control key down, click the text view and drag down to the tvwTest outlet in the ViewController.h file. When the Connect Outlet popup appears (Figure 8.50), release the mouse key to create the connection to the outlet.

    Figure 8.50 Connect the text view to the tvwTest outlet.

  16. Now let’s see how these controls look at run time. Click Xcode’s Run button, and when the App appears in the Simulator, it looks just as it does at design time (except there is descriptive text in the text view).

  17. Go to the Simulator menu and select Hardware > Rotate Left. As shown in Figure 8.51, the image view is pinned to the left side of the view and the text view is pinned to the right.
  18. Figure 8.51 The text view & image view in landscape mode


This is exactly what is specified by the constraints, but not exactly what we want. There is a lot of empty space in the middle of the view that should be filled by increasing the width of the image view and text view. Let’s fix that now.


  1. Go back to Xcode and click the Stop button.

  2. To turn off the Assistant Editor, go to the Xcode toolbar at the top of the window and click the left button in the Editor button group.

  3. Click on the image view in the design surface to select it, then hold the Shift key down and click on the text view to select it too.

  4. At the bottom of the Interface Builder editor are several buttons that provide quick access to commonly used features. The three button group highlighted in Figure 8.52 provides access to Auto Layout options.
  5. Figure 8.52 Interface Builder Auto Layout buttons

    Click the center button in this button group. As you can see in Figure 8.53, this provides a variety of Pin options.

    Figure 8.53 Create a Horizontal Spacing constraint.

    Select Horizontal Spacing to pin the spacing between the image view and text view to its current value of zero points. This creates a new Horizontal Space constraint that you can see in the Document Outline pane (Figure 8.54), although oddly enough, it doesn’t appear in the Size Inspector.

    Figure 8.54 The new Horizontal Space constraint

  6. Let’s run the App to see how it looks at run time. Click Xcode’s Run button, and when the App appears in the Simulator, select Hardware > Rotate Left from the Simulator menu. As you can see in Figure 8.55, there is zero space between the image view and the text view!

  7. Figure 8.55 Zero space between the image view and text view.


In just a bit, you will learn how to evenly divide the available space between the image view and text view, but for now, we’re going to fix a problem with conflicting constraints.


Resolving Constraint Conflicts


Did you notice that when you rotated the App in the Simulator, the warnings shown in Figure 8.56 were displayed in the Console?

Figure 8.56 Conflicting constraints warning

Even though the final result of the resizing and positioning of controls was correct, the Auto Layout system found conflicts in the constraints.

The message at the top of Figure 8.56 says: “Unable to simultaneously satisfy constraints.” The next paragraph states “Probably at least one of the constraints in the following list is one you don’t want.” Further down, it lists the group of constraints in which there is a conflict, and near the bottom it tells you which constraint it broke to try and recover from the conflict. 

This is a great feature of Auto Layout. Even though there are conflicting constraints, it does its best to come up with a best guess for a solution by breaking one of the conflicting constraints.

Looking through the list of constraints should give you a pretty good idea where the conflict lies. The constraints are displayed in the syntax of Apple’s Visual Format Language. Here is some of the basic syntax of this language (for more information, check out the topic Visual Format Language in the Apple documentation):

  • A control is represented between square brackets.

  • A connection between controls and views is represented by a single hyphen, or two hyphens with a number in between representing the space between the objects in points.

  • The superview or parent view is represented by a single vertical line.

For example, look at the second half of the first constraint:

H:[UITextView:0x79f3000(130)]

  • The H indicates this constraint applies to a horizontal orientation.

  • The UITextView between square brackets indicates this constraint applies to a text view.

  • The (130) indicates the value associated with the constraint.

From this information you can derive that this is the text view’s width constraint. As you look through the other constraints, it’s pretty easy to see the problem. The constraints dictate that:

  • The text view must be 130 points wide

  • The image view must be 150 points wide

  • There must be 20 points between the left side of the view and the left side of the image view

  • There must be zero space between the image view and text view

  • There must be 20 points between the right side of the text view and the right side of the view.

When the device is in portrait orientation, all of these constraints can be satisfied. However, when the device is rotated to landscape orientation and the view becomes wider, not all of these constraints can be satisfied. For that reason, the Auto Layout system decided to break the image view’s width constraint:

Will attempt to recover by breaking constraint 

<NSLayoutConstraint:0x892e8f0 H:[UIImageView:0x892e790(150)]>

Even if you agree with the decision made by the Auto Layout system, you should still fix the conflict so your constraints are simplified and efficient. Let’s do that now.

  1. In Xcode, click the Stop button to stop the App from running in the Simulator.

  2. Select the image view in the design surface.

  3. Go to the Size Inspector and locate the Width Equals: 150 constraint.

  4. Click the small down arrow on the right side of the constraint and select Select and Edit… from the popup menu. This displays the Attributes Inspector.

  5. Change the Relation attribute to Greater Than or Equal (Figure 8.57). This indicates the image view can be greater than or equal to 150 points. Now the constraints can be satisfied in both portrait and landscape modes.
  6. Figure 8.57 Set the Relation to Greater Than or Equal.

  7. Let’s see how this work at run time. Click Xcode’s Run button, and when the App appears in the Simulator, select Hardware > Rotate Left from the menu. You should no longer see any constraint errors in the Console!

Let’s look at another example that will provide another opportunity to resolve a constraint conflict. In this example, you will make the image view and text view equal in width.

  1. Select the image view in the design surface, and then go to the Size Inspector (second button from the right in the Inspector toolbar).

  2. Change the image view’s Width attribute to 140. When you do this, the image view’s width constraint changes from a user constraint back to an automatic constraint of Width Equals: 140 (Figure 8.58).
  3. Figure 8.58 The image view’s width constraint

  4. Select the text view in the design surface. Grab the resizing handle on the left side of the text view and move it left until the text view’s width is 140 points (Figure 8.59).
  5. Figure 8.59 Resize the text view’s width to 140 points.

  6. When you resized the image view, the horizontal space constraint between the image view and text view was removed by Interface Builder. To put it back, select the text view in the design surface, hold down the Shift key, and then click the image view to select it. Rather than using the Auto Layout buttons at the bottom-right corner of the Interface Builder editor, go to Xcode’s menu and select Editor > Pin > Horizontal Spacing (it performs the exact same function, but I just wanted to show you how to select it from the menu). 

  7. When you create a constraint between two controls as you just did, they become unselected in the design surface, so let’s select both of them again. Click the image view to select it, then hold down the Shift key and click the text view to select it. 
  8. In the Xcode menu, select Editor > Pin > Widths Equally. When you do this, a new equal widths constraint is added to the view (Figure 8.60). Notice there is an equal sign inside a circle under the image view and the text view representing the equal width constraint.

    Figure 8.60 The new equal widths constraint.

  9. Let’s run the App to see how it looks. Click Xcode’s Run button. When the App appears in the Simulator, the image view and text view will be sized and positioned just as they are at design time.

  10. In the Simulator menu, select Hardware > Rotate Left, and the image view and text view should be equal sizes (Figure 8.61).
  11. Figure 8.61 The text view and image view are equal widths.

This works exactly as it should, but you may have noticed there were constraint conflict errors displayed in the Console again. Let’s take a closer look to see how these can be fixed.

Figure 8.62 shows the constraint debugging information displayed in the Console.

Figure 8.62 The new set of constraint conflicts

  • There must be 20 points between the left side of the view and the left side of the image view.

  • The image view and text view are the same width.

  • There must be 20 points between the right side of the view and the right side of the text view.

  • There must be zero space between the image view and the text view.

  • The text view must be 140 points wide.

Can you spot the problem? Ultimately, this is very similar to the constraint conflicts you saw earlier. The text view is constrained to be 140 points and the image view is constrained to be the same size as the text view. This is fine when in portrait mode, but it’s not possible in landscape mode.

When you fixed the problem last time, you changed the width constraint from Equal to Greater Than or Equal. This time we’re going to do something different.

  1. Go back to Xcode and click the Stop button.

  2. In the Document Outline pane, expand the Image View’s and Text View’s Constraints nodes. Notice each control has a Width constraint (Figure 8.63) that is blue, indicating it is a user control. The great thing about user controls, is they can be deleted (automatic constraints created by Interface Builder cannot be deleted).
  3. Figure 8.63 The Width constraints

  4. First of all, since there is a constraint that says the image view is the same width as the text view, there’s no need for the image view to have a width constraint. So, click on the Image View’s Width constraint in the Document Outline pane and press the Delete key to delete it.

  5. You may think that the text view still needs its width constraint, but because of the presence of the Equal Widths constraint, it doesn’t! 

  6. Let’s see how this works at run time. Click Xcode’s Run button, and when the App appears in the Simulator, select Hardware > Rotate Left from the menu. As you can see, the image view and text view take up an equal amount of space in the view, and there are no constraint warnings in the Console!
  7. Click on the Text View’s Width constraint in the Document Outline pane and then press Delete to delete it.

  8. Let’s see how this works at run time. Click Xcode’s Run button, and when the App appears in the Simulator, select Hardware > Rotate Left from the menu. As you can see, the image view and text view take up an equal amount of space in the view, and there are no constraint warnings in the Console!

As you lay out your own user interfaces in Xcode using Auto Layout, I recommend looking very carefully at the constraints that have been added to your scenes and remove those that are not necessary.

Kevin McNeish
Author: iOS App Development for Non-Programmers book series 
Twitter: @kjmcneish
 

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>