1, What’s Auto Layout

Auto Layout is a library provided by Apple’s UIKit framework for dynamically calculating the size and position of UIViews and their subclasses.

Speaking of Auto Layout, we have to say Cassowary algorithm, because Auto Layout is built on the basis of Cassowary algorithm. In 1997, the Layout algorithm used by Auto Layout was published, which is called efficient linear equation solving algorithm. In 2011, Apple used the Cassowary algorithm to provide developers with an Auto Layout library. Due to the excellent Cassowary algorithm itself, not only apple, many developers have applied Cassowary algorithm in different development languages, such as JavaScript, ASP.NET, Java, C++, etc. There are libraries using Cassowary algorithm. It can also be seen from this that Cassowary’s algorithm is excellent and advanced, otherwise it would not be so widely used.

Apple introduced Auto Layout in iOS 6, but now that iOS 12 has been updated, many developers still don’t want to use Auto Layout. Mostly concerns about its anti-human syntax and performance issues.

In response to some of the problems with Auto Layout, Apple introduced NSLayoutAnchor with a cleaner syntax when iOS 9 was released. UIStackView, which mimics the layout ideas of the front Flexbox, was also released to provide developers with better options for automatic layout.

At apple,WWDC 2018 High Performance Auto LayoutAccording to Apple engineers, iOS 12 will significantly improve Auto Layout performance by allowing you to swipe to full frames. inWWDC 2018 What’s New in Cocoa TouchApple engineers talked about iOS 12’s Auto Layout improvements.As you can see from the picture,iOS 11The number of nested views in view has increased exponentially in performanceiOS 12The performance of a handwritten frame layout is basically similar.

From iOS 6 to iOS 12, Apple has been continuously improving The performance of Auto Layout and providing developers with simpler apis. If you still use Frame handwriting Layout, try Auto Layout. Here are a few common layout methods used on iOS.

2. Different versions of Auto Layout are used differently

If I wanted to create a View with a width and height of 120 and a center View, it would look like this:

1. Use frame handwriting for layout
    UIView *centerView = [[UIView alloc] init];
    centerView.backgroundColor = [UIColor redColor];
    [self.view addSubview:centerView];
    CGFloat width = self.view.frame.size.width;
    CGFloat height = self.view.frame.size.height;
    [centerView setFrame:CGRectMake(width / 2 - (60), height / 2 - (60), 120, 120)];
Copy the code
Add constraints to the NSLayoutConstraint syntax provided in iOS 6
centerView.translatesAutoresizingMaskIntoConstraints = NO; NSLayoutConstraint *consW = [NSLayoutConstraint constraintWithItem:centerView attribute:NSLayoutAttributeWidth RelatedBy: NSLayoutRelationEqual toItem: self. The view attribute: NSLayoutAttributeWidth multiplier: 0 constant: 120.0]; NSLayoutConstraint *consH = [NSLayoutConstraint constraintWithItem:centerView attribute:NSLayoutAttributeHeight RelatedBy: NSLayoutRelationEqual toItem: self. The view attribute: NSLayoutAttributeHeight multiplier: 0 constant: 120.0]; NSLayoutConstraint *consX = [NSLayoutConstraint constraintWithItem:centerView attribute:NSLayoutAttributeCenterX RelatedBy: NSLayoutRelationEqual toItem: self. The view attribute: NSLayoutAttributeCenterX multiplier: 1.0 constant: 0.0]; NSLayoutConstraint *consY = [NSLayoutConstraint constraintWithItem:centerView attribute:NSLayoutAttributeCenterY RelatedBy: NSLayoutRelationEqual toItem: self. The view attribute: NSLayoutAttributeCenterY multiplier: 1.0 constant: 0.0]; [self.view addConstraints:@[consW,consH,consX,consY]];Copy the code
3. Use VFL grammar
 centerView.translatesAutoresizingMaskIntoConstraints = NO;
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[centerView(120)]" options:0 metrics:nil views:views]];
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"[centerView(120)]" options:0 metrics:nil views:views]];
    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:centerView attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterY multiplier:1 constant:0]];
    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:centerView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1 constant:0]];
Copy the code
4. Use third-party open source frameworksMasonryorSnapKit
 __weak typeof (self) weakSelf = self;
 [centerView mas_makeConstraints:^(MASConstraintMaker *make) {
     make.size.mas_equalTo(CGSizeMake(120, 120));
     make.center.equalTo(weakSelf.view);
 }];

Copy the code
 let centerView:UIView = UIView.init()
 view.addSubview(centerView)
 centerView.backgroundColor = UIColor.red
 centerView.snp.makeConstraints { (make) in
    make.width.equalTo(120)
    make.height.equalTo(120)
    make.center.equalTo(view)
 }
Copy the code
5. Provided by Apple after using iOS 9NSLayoutAnchor
 let centerView:UIView = UIView.init()
 view.addSubview(centerView)
 centerView.backgroundColor = UIColor.red
 centerView.translatesAutoresizingMaskIntoConstraints = false
 centerView.centerXAnchor.constraint(equalTo: view.centerXAnchor, constant: 0).isActive = true
 centerView.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: 0).isActive = true
 centerView.widthAnchor.constraint(equalToConstant: 120).isActive = true
 centerView.heightAnchor.constraint(equalToConstant: 120).isActive = true
Copy the code

Using the NSLayoutConstraint syntax and VFL syntax is the most complex, especially the NSLayoutConstraint syntax, which requires 30 + lines of code to achieve the same effect. The more lines of code you have, the more likely you are to get an error, which is one of the reasons why many developers don’t want to use Auto Layout (or the API provided by the system).

For apps compatible with iOS 9 and below, I suggest you post it. For apps compatible with iOS 9 and above, I suggest you post SnapKit or the NSLayoutAnchor API. After all, the library for navigation has not been updated for two years.

Here, I recommend the use of NSLayoutAnchor in preference. Third-party open source libraries are always confronted with some problems:

  • iOSThe adaptation and compatibility problems caused by the update of the system version, if it is open source code, apple will release the new version, and the author of the code will do the compatibility and adaptation
  • The author of the code stops updating the code, which makes it very passive for us developers to either modify the code ourselves or choose the newer open source code
  • Using system libraries can reduce package size when packaging

3,Auto LayoutLife cycle of

As mentioned above, Apple’s Auto Layout is based on Cassowary algorithm. On this basis, Apple provides a Layout Engine to manage the Layout of the page, to complete the creation, update, destruction and so on.

After the APP is started, a resident thread will be started to listen for the change of the constraint. When the constraint changes, it will Deffered Layout Pass(delayed Layout Pass) and perform fault tolerance processing (such as some views did not confirm or missing Layout declaration when updating the constraint). After completion, it will enter the state of constraint monitoring change.

The next time a view is refreshed (such as a call to layoutIfNeeded()), the Layout Engine calls layoutSubviews() from top to bottom and calculates the size and location of each subview through the Cassowary algorithm. Then copy the subview frame from the layout Engine, and the process is the same as drawing and rendering the frame by hand. Most of the work with Auto Layout and handwritten frames is in Layout calculations.

4,NSLayoutAnchorCommonly used attributes

  • leadingAnchor
  • trailingAnchor
  • leftAnchor
  • rightAnchor
  • topAnchor
  • bottomAnchor
  • widthAnchor
  • heightAnchor
  • centerXAnchor
  • centerYAnchor
  • firstBaselineAnchor
  • lastBaselineAnchor

For some common attributes of NSLayoutAnchor, its functions can be seen through its naming, which will not be described here. If you want to know more, please refer to Apple Developer NSLayoutAnchor.

5, Auto Layout several update constraint methods

  • SetNeedsLayout: Tells the page that it needs to be updated, but does not start updating immediately. LayoutSubviews is called immediately after execution.

  • LayoutIfNeeded: Notifies the page layout to be updated immediately. So it’s usually used with setNeedsLayout. You need to call this method if you want to generate a new frame immediately, so you can use this method to animate a general layout animation after updating the layout.

  • LayoutSubviews: Updates subview constraints

  • SetNeedsUpdateConstraints: need to be updated, but not immediately start

  • UpdateConstraintsIfNeeded: immediately update the constraints

  • UpdateConstraints: Updates the View constraints

6,NSLayoutAnchorPrecautions for Use

1. In useNSLayoutAnchorWhen adding constraints to a view, make sure that thetranslatesAutoresizingMaskIntoConstraintsSet up thefalse
 centerView.translatesAutoresizingMaskIntoConstraints = false
Copy the code
2. In usesafeAreaLayoutGuideadapteriPhone XWait for the right modeliOS 11Previous system adaptation, otherwise it will lead to Crash on the lower version of the system
# if available (iOS 11.0. *) {tableView. TopAnchor. The constraint (equalTo: self. View. SafeAreaLayoutGuide. TopAnchor, constant: 0).isActive = true } else { tableView.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 0).isActive = true }Copy the code
3. Activate the constraint after setting itisActivefortrue
let centerX: NSLayoutConstraint = centerView.centerXAnchor.constraint(equalTo: view.centerXAnchor, constant: 0)
centerX.isActive = true
Copy the code
4,leadingAnchorDon’t get along withleftAnchorA mixture of
centerView.leadingAnchor.constraint(equalTo: view.leftAnchor, constant: 0).isActive = true
Copy the code
centerView.leftAnchor.constraint(equalTo: view.leadingAnchor, constant: 0).isActive = true
Copy the code

Error code: error code: error code: error code: error code: error code: error code

While the NSLayoutAnchor class provides additional type checking, it is still possible to create 
invalid constraints. For example, the compiler allows you to constrain one view’s leadingAnchor
 with another view’s leftAnchor, since they are both NSLayoutXAxisAnchor instances. However, 
Auto Layout does not allow constraints that mix leading and trailing attributes with left or right 
attributes. As a result, this constraint crashes at runtime.
Copy the code

Likewise, trailingAnchor and rightAnchor should not be used together.

5. How to refresh a constraint

For example, if I want to change the width of a UIView, I can add the UIView width to the class property, and then change the constant parameter where necessary, and then refresh the constraint, as follows:

 var centerView: UIView! 
 var centerWidth: NSLayoutConstraint! 

Copy the code

self.centerView = UIView.init()
view.addSubview(self.centerView)
self.centerView.backgroundColor = UIColor.red
self.centerView.translatesAutoresizingMaskIntoConstraints = false
self.centerView.centerXAnchor.constraint(equalTo: view.centerXAnchor, constant: 0).isActive = true
self.centerView.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: 0).isActive = true
self.centerWidth = self.centerView.widthAnchor.constraint(equalToConstant: 120)
self.centerWidth.isActive = true
self.centerView.heightAnchor.constraint(equalToConstant: 120).isActive = true
Copy the code
Self. CenterWidth. Constant = 250 weak var weakSelf = self UIView. The animate (withDuration: 0.35, animations: {weakSelf? .centerView.superview? .layoutIfNeeded() }) { (finished) in }Copy the code

The effect is as follows:

If it isxiborstoryboard“Then it’s even easier. Just press the keyboardcontrolKey, drag it to the corresponding class, and then modify and refresh the constraints where necessary. The operation is as follows:

6, set the width to height ratio

During the development, we will meet some requirements to set constraints according to the aspect ratio of UIView. For example, in general, the aspect ratio of displaying videos is 16:9. Set the aspect ratio by code as follows:

 centerView.heightAnchor.constraint(equalToConstant: 90).isActive = true
 centerView.widthAnchor.constraint(equalTo: centerView.heightAnchor, multiplier: 16 / 9).isActive = true
Copy the code

7,Auto LayoutThe adaptiveUITableViewCellHigh usage

1, use,rowHeightSet the height

In general, if the height of each Cell of a UITableView is fixed we can specify a value, but if the height of the UITableView is not set, the system will default to the rowHeight height of 44.

tableview.rowHeight = 44;
Copy the code

You can also set the height of the UItableView via the UITableViewDelegate delegate.

 func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 50
 }
Copy the code

If you manually calculate the height of each UItableViewCell, also implemented in this proxy, return the height of each UItableViewCell by calculating the height.

2, use,estimatedRowHeightSet the height

UItableView inherited from UIScrollView, UIScrollView roll need to set up after the contentSize, then according to the bounds of oneself, contentInset, contentOffset property to compute the length of a scrollable. The UITableView does not know these parameters at initialization, but only after setting the delegate and dataSource can it calculate the scrollable length based on the number of uITableViewCells created and the height of the loaded UITableViewCell.

When using Auto Layout to adapt the height of the UITableViewCell, you should set an estimate in advance. The closer the estimate is to the true value, the better.

 tableView.rowHeight = UITableView.automaticDimension
 tableView.estimatedRowHeight = 200
Copy the code
 func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
    return 200    
 }
Copy the code

As shown above: This interface uses Auto Layout + estimatedRowHeight to complete the adaptive height. When adding constraints, the distance from the top (top) of each UIView to the bottom (bottom) of the previous view should be set according to the information from top to bottom. We also calculate the height of all the controls inside the UITableViewCell. The problem is that the height cannot be calculated before the details of the content posted by users are provided with data. Here, you can set a default height for the content text UILabel and let it automatically calculate the height according to the content filling:

 topicInfoLab.heightAnchor.constraint(greaterThanOrEqualToConstant: 20).isActive = true;
 topicInfoLab.font = UIFont.init(name: "Montserrat-SemiBold", size: 12)
topicInfoLab.numberOfLines = 0
Copy the code

If the user posts the content without an image, set the distance from the UILabel to the bottom of the UITableView constraint.

 detailsLab.bottomAnchor.constraint(equalTo: self.contentView.bottomAnchor, constant: -8).isActive = true

Copy the code

If the user posts with images, be sure to set the constraint distance from the bottom of the UItableViewCell to the last image after calculating the position and size of each image.

for(idx, obj) in imageArray.enumerated() { //..... To calculate the size of the picture and location if independence idx = = imageArray. {count - 1 / / set the last image distance constraint at the bottom of the photo. The bottomAnchor. The constraint (equalTo: self.contentView.bottomAnchor, constant: -8).isActive = true } }Copy the code

Implementation ideas as shown in the figure above, see the code for specific implementation

Eight,Compression Resistance PriorityHugging Priorityuse

Compression Resistance Priority and Hugging Priority tend to be used in conjunction in practical use, which respectively deal with the squeezing situation caused by too little and too much content among multiple views on a synonymous horizontal line.

Hugging Priority Means the Priority of self-wrapping, and the higher the Priority, the size will be padded according to the content of the control.

Compression Resistance Priority, which means cutting according to this Priority when there is not enough content to display. The lower the priority, the easier it is to cut.

ContentHuggingPriority Represents the currentUIViewContent doesn’t want to be stretched
ContentCompressionResistancePriority Represents the currentUIViewContent does not want to be shrunk
By default:HuggingPriority = 250 By default:CompressionResistancePriority = 750

To set the stretching priority of 2 Uilabels, use code:

fristLab.setContentHuggingPriority(UILayoutPriority(rawValue: 251), for: .horizontal)
secondLab.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 750), for: .horizontal)
Copy the code

9,

This paper mainly shares several implementation methods and matters needing attention of Apple Auto Layout. Whether to use Auto Layout in actual development by pure code, XIB + code or Storyboard + code, Or xiB + Storyboard + code, depending on the requirements of the team, personal habits, and the complexity of the App. For the use of Auto Layout on the view, I recommend using Auto Layout for a simple UI or a single interface. For the operation or refreshing of a complex UI, I recommend using Frame + manual Layout.


This article demo, please stamp here

Links:

Analyze Auto Layout and new features of iOS versions

How does Auto Layout carry out automatic Layout and its performance?

Apple Developer High Performance Auto Layout

Apple Develope NSLayoutConstraint

WWDC 2018 What’s New in Cocoa Touch