Implementing Cross-Hierarchy Auto Layout Constraints in iOS 8

From Techotopia
Revision as of 14:36, 5 May 2016 by Neil (Talk | contribs) (Text replacement - "<table border="0" cellspacing="0" width="100%">" to "<table border="0" cellspacing="0">")

Jump to: navigation, search
PreviousTable of ContentsNext
Implementing iOS 8 Auto Layout Constraints in Swift CodeUnderstanding the iOS 8 Auto Layout Visual Format Language in Swift


Learn SwiftUI and take your iOS Development to the Next Level
SwiftUI Essentials – iOS 16 Edition book is now available in Print ($39.99) and eBook ($29.99) editions. Learn more...

Buy Print Preview Book


One of the few types of Auto Layout constraint that cannot be implemented within the Interface Builder environment is one that references views contained in different view hierarchies. Constraints of this type must, therefore, be implemented in code. Fortunately, however, the steps to achieve this are quite simple. The objective of this chapter is to work through an example that demonstrates the creation of a cross-view hierarchy Auto Layout constraint.


Contents


The Example Application

For the purposes of this example, a very simple user interface will be created consisting of two Views, a Button and a Label. In terms of the physical view hierarchy, the user interface will be constructed as outlined in Figure 22-1.


Autolayout cross View heirarchy.png

Figure 22-1


The goal will be to implement a constraint that aligns the centers of the Button and Label which are part of different view hierarchies - the button being part of the hierarchy contained by View A and the label being part of the View B sub-hierarchy.

In terms of visual layout, the user interface should appear as illustrated in Figure 22-2. Key points to note are that the label should have constraints associated with it which horizontally and vertically center it within View B and the button view should be positioned so that it is off center in the horizontal axis:


Ios 8 crossview ui.png

Figure 22-2


Begin by launching Xcode and selecting the options to create a new iOS application based on the Single View Application template. Enter CrossView as the product name and set the Device and Language menus to Universal and Swift respectively.

Select the Main.storyboard file from the project navigator panel, select the view and change the background color to a light shade of grey using the Attributes Inspector. Drag and drop UIView, Button and Label views onto the design canvas as illustrated in Figure 22-2, making sure to center the label object horizontally and vertically within the parent view.

Select the newly added view object, click on the Resolve Auto Layout Issues menu from the toolbar in the lower right hand corner of the canvas and select the Reset to Suggested Constraints option listed under All Views in View Controller.

Establishing Outlets

In order to set a cross hierarchy constraint within code, it will be necessary to implement some outlets. Since the constraint will need to reference both the button and the label, outlets need to be configured for these views. Select the label object and display the Assistant Editor using the View -> Assistant Editor -> Show Assistant Editor menu option or by selecting the center button (the one containing an image of two interlocking circles) of the row of Editor toolbar buttons in the top right hand corner of the main Xcode window. Make sure that the Assistant Editor is showing the ViewController.swift file. Ctrl-click on the Label object in the view and drag the resulting line to the area immediately beneath the class declaration directive in the Assistant Editor panel. Upon releasing the line, the connection panel will appear. Configure the connection as an Outlet named myLabel and click on the Connect button. Repeat the above steps to add an outlet for the button object named myButton.

As currently constrained, the label object is centered horizontally within the view we are referring to as View B. In place of this constraint, we need the label to be aligned with the center of the button object. This will involve removing the CenterX constraint and replacing it with a new constraint referencing the button. This requires outlets for both the View B instance and the CenterX constraint.

Ctrl-click on the View B parent of the label object and drag the resulting line to the area immediately beneath the previously declared outlets in the Assistant Editor. Release the line and configure an outlet named viewB.

Next, select the label object so that the associated constraint lines appear. Click on the vertical line passing through the label view so that it highlights. Ctrl-click on the constraint line and drag to the Assistant Editor panel (Figure 22 3) and create a new outlet for this object named centerConstraint.


Xcode 6 constraint outlet.png

Figure 22-3


Writing the Code to Remove the Old Constraint

With the necessary outlets created, the next step is to write some code to remove the center constraint from the label object. For the purposes of this example, all code will be added to the viewDidLoad method of the view controller. Select the ViewController.swift file and locate and modify the method as follows:

override func viewDidLoad() {
    super.viewDidLoad()
    viewB.removeConstraint(centerConstraint)
}

All that the code is doing is calling the removeConstraint method of view B using the previously configured outlet, passing through a reference to the CenterX constraint, once again using the previously configured outlet to that object.

Adding the Cross Hierarchy Constraint

All that remains is to add the constraint to align the centers of the label and button. With the appropriate outlets already configured, this is simply a matter of creating the NSLayoutConstraint object with the appropriate values, and adding it to the closest common ancestor:

override func viewDidLoad() {
    super.viewDidLoad()

    viewB.removeConstraint(centerConstraint)

    let constraint =
        NSLayoutConstraint(item: myLabel,
            attribute: NSLayoutAttribute.CenterX,
            relatedBy: NSLayoutRelation.Equal,
            toItem: myButton,
            attribute: NSLayoutAttribute.CenterX,
            multiplier: 1.0,
            constant: 0.0)

    self.view.addConstraint(constraint)
}

Testing the Application

Compile and run the application either on a physical iOS device, or using the iOS Simulator. When the application is running, the label view should be aligned with the button and this alignment should be maintained when the device is rotated into landscape orientation.

Summary

The current version of Interface Builder does not provide a way to select two views that reside in different view-hierarchies and configure a constraint between them. The desired result can, as outlined in this chapter, be achieved in code. Of key importance in this process is the fact that constraints, just like any other view object in a user interface, may be connected to an outlet and accessed via code.


Learn SwiftUI and take your iOS Development to the Next Level
SwiftUI Essentials – iOS 16 Edition book is now available in Print ($39.99) and eBook ($29.99) editions. Learn more...

Buy Print Preview Book



PreviousTable of ContentsNext
Implementing iOS 8 Auto Layout Constraints in Swift CodeUnderstanding the iOS 8 Auto Layout Visual Format Language in Swift