Monday, April 1, 2019

Auto layout and Constraints in iOS

Layout is the way in which the UI components (UIView, UIButton, UILabel) are arranged together. Auto layout means the UI components dynamically change their sizes and positions according to external or internal changes such as the screen rotates. We have to define constraints for those UI components either in Interface Builder or programmatically so that they know how to change in different situations. For example, we can set a constraint for a button to always stay in the center of the screen both horizontally and vertically.

We must set enough constraints for each UI control added or we will get unexpected result like the control shows up in portrait mode but doesn't in landscape mode. 

How to know what constraints should be set? It's based on circumstances. Logically, the system must know the UI control's position and size so the constraint should tell enough information about the size and position. However, if we specify constraints for the top, leading, bottom, and trailing edges of an image view equal to its superview's, we don't have to specify its size because that's enough for the system to know its size. its size will always be the same as its superview's size.



Traditionally, without auto layout, the developers must calculate the size and position of a view's frame and its subview's frame. Then, when the screen's size changes, they have to recalculate the frame's sizes and positions for the view and its subviews.


Adding Constraints in Interface Builder


1). Drag a UIView object from the Object Library and drop it in the View Controller's view.


2). Control-drag the subview to the ViewController's view and select "Leading Space to Safe Area" from the popup.



Then, select the subview and open the Size Inspector and the leading constraint would appear there.


In my case, the leading space is 62 because I dropped the subview at that position. We can change it though by selecting the constraint in the Size Inspector and click Edit then update the Constant to 0 so that the subview's leading edge equal to the superview's leading edge.

3). Repeat Step 2 to set 3 more constraints for the subview by selecting "Top Space to Safe Area", "Trailing Space to Safe Area", and "Bottom Space to Safe Area" when the pop up appears. The image below shows the result of this step.



It's finished for our purpose here. The subview will dynamically change its size to maintain the defined spaces between its edges and the superview's.


Adding Constraints Programmatically


1). Control-drag the subview to the SecondViewController.swift in my case, to create an outlet so that we can access the subview from code


2). The constraints should be set in ViewController's viewDidLoaded() method as following:
    
import UIKit

class SecondViewController: UIViewController {
    
    @IBOutlet weak var view1: UIView!
    
    override func viewDidLoad() {
        view1.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
        view1.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
        view1.trailingAnchor.constraint(equalTo: self.view.trailingAnchor).isActive = true
        view1.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true
        view1.translatesAutoresizingMaskIntoConstraints = false
    }
}
    

The leadingAnchor, topAnchor, trailingAnchor, and bottomAnchor properties represent the leading, top, trailing, and bottom edges of the view's frame, respectively.

Note that if we have the constraints set both in Interface Builder and programmatically, the ones in Interface Builder take effect. If we want to programmatically modify the constraints defined in Interface Builder, we have to create the outlets connected the constraints from Interface Builder and modify them in viewDidLoad() method.

Layout Margins
We can define the constraints relative to the superview's margin instead. See here for more details.



No comments:

Post a Comment