preface

AutoLayout for layout is nothing new, and I’ve written three introductory articles before.

  • IB automatic generation

  • The IB drag

  • Code implementation

Of course, in real development, storyboards and XIB files are basically discarded if you’re working with multiple people. Because these two files are essentially XML, it can be a pain to have multiple people working together to modify such large XML.

So, most of the time, Layout constraints are implemented in pure code.

Unless some company wants to implement its own Layout engine. Otherwise, it’s more about using third-party libraries.

  • Masonry

Using NAVIGATION makes constraint creation easy. However, in order to take advantage of AutoLayout, there are a number of constraints that you need to know to help you achieve more complex and flexible layouts.

Constraint priority

NSLayoutConstraint has a priority attribute of type UILayoutPriority, which is essentially a float

typealias UILayoutPriority = Float    

You can go to the following values, or you can set the float value directly

enum {    

   UILayoutPriorityRequired = 1000,    

   UILayoutPriorityDefaultHigh = 750,    

   UILayoutPriorityDefaultLow = 250,    

   UILayoutPriorityFittingSizeLevel = 50,    

};    

typedef float UILayoutPriority;    

Usefulness: Breaks the lower priority constraint when two constraints conflict

Here’s an example:

For example, I’d like to have a View like this

  • Horizontal and vertical center

  • Width 320, height 200

  • The minimum distance between left and right is greater than or equal to 20 (for small screens)

At this point, add the following constraints:

Review images

Then, let’s look at the preview

Review images

On the 4S, the preview wasn’t correct, but on the larger screen, everything worked.

If you run the 4S emulator at this point, you’ll find Log

OCTest[1004:26277] Unable to simultaneously satisfy constraints.

    Probably at least one of the constraints in the following list is one you don’t want.     

    Try this:     

        (1) look at each constraint and try to figure out which you don’t expect;     

        (2) find the code that added the unwanted constraint or constraints and fix it.     

(    

    “=20)-[UIView:0x79159c70]   (Names: ‘|’:UIView:0x79158e50 )>”,    

    “”,    

    “”,    

    “”    

)    

   

Will attempt to recover by breaking constraint     

   

   

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.    

The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in may also be helpful.    

It’s not hard to see why:

  • The width of the screen on the 4S is 320, and the width of the View is 280 or less to ensure that the left and right border of the View is greater than or equal to 20

  • The View also has a constraint of 320 width

This is where the priority comes in. We set the priority of the width lower so that when a constraint conflicts with the width, the default is break the width constraint.

On IB, you can set it like this:

Since the default priority is 1000, we only need to set it to 999 here.

Review images

Then, the preview and run are fine

Review images

On IB, if you see a constraint represented by a dotted line, then the constraint has a lower priority than the default.

Intrinsic Size

And we know that UILabel and UIButton, when you set constraints, you just have to specify the position, you don’t have to specify the size constraint. Because UI labels and UI Buttons have intrinsic sizes.

Intrinsic size is a method of UIView, that is, you can return custom intrinsic size for UIView and its subclasses by inheritance.

-(CGSize)intrinsicContentSize{    

    return [super intrinsicContentSize];    

}    

A typical example is if I center horizontal and vertical for just one UIView

Review images

At this point, you’ll notice that the constraint is red, which is thetaAutolayout cannot confirm the state of the view.

Intrinsically set the Intrinsic size to 300 x 200 on IB. The Intrinsic size option is displayed at the bottom of the figure below.

Review images

After setting, IB is normal.

This setting does not affect runtime, only removes IB warnings.

So, let’s create a UIView subclass, and change the class of that view.

@interface AutoAdjustView : UIView    

@end    

@implementation AutoAdjustView    

-(CGSize)intrinsicContentSize{    

    return CGSizeMake(300, 200);    

}    

@end    

Everything was found to be fine during the run.

There are two common usage scenarios for Intrinsic Size

Scenario 1, set additional Padding for UILabe, UIButton, etc

For example, a default UIButton, after setting text, looks something like this

Review images

When we write a subclass, override intrinsicContentSize

@implementation RoundButton    

   

-(CGSize)intrinsicContentSize{    

    CGSize size = [super intrinsicContentSize];    

    size.width += size.height;    

    return size;    

}    

-(void)layoutSubviews{    

    [super layoutSubviews];    

    self.layer.cornerRadius = ceil(self.bounds.size.height/2);    

    self.layer.masksToBounds = YES;    

}    

@end    

So it looks something like this, and you can see that we’ve added some extra padding regardless of the actual width.

Review images

Scenario 2, let the parent view adapt its size to the child view (I drag and drop on IB for convenience, code implementation is similar)

First, drag and drop a view with a blue background as the parent view, and then add a label to the parent view.

Superview Settings

  • Horizontal and vertical center

  • Intrinsic Size is 0,0

The setting of the Label

From the top, bottom, leading, trailing, a distance of 20

Review images

At this point, preview as follows (just modify the label text)

Review images

Review images

As you can see, we have not set the height and width of the blue view, which can be adapted to contain the view internally.MBProgressHUDThat’s what you do with the adaptive size of the middle region.

Hugging Priority

UIView has a method that is

setContentHuggingPriority: forAxis:    

Sets the priority with which a view resists being made larger than its intrinsic size. Sets the priority with which a view resists being made larger than its intrinsic size The higher the priority, the stronger the resistance)

   

Where priority is UILayoutPriority, same as above. Axis is the coordinate system

typedef NS_ENUM(NSInteger, UILayoutConstraintAxis) {    

    UILayoutConstraintAxisHorizontal = 0,    

    UILayoutConstraintAxisVertical = 1    

};    

That is, you can set the horizontal and vertical priorities separately.

For example

IB drags the red and blue views

The blue Settings are as follows

  • Distance from top 8

  • 20 to the left

  • Built-in size 120 * 50

The 4.7-inch screen preview is shown below

Review images

Next, add a horizontal interval of 10 between the two views.

As you can see, the constraints conflict because both views have the same tensile priority.

Review images

Since the default priority value is 250, we select the blue View and set the priority to 249 to stretch the blue View itself, and 251 to stretch the red View.

Review images

Compression Resistance Priority

Sets the priority with which a view resists being made smaller than its intrinsic size. In other words, it seems similar to the Hugging Priority mentioned above, except that it seems to be a compression Priority. Here’s another example.

– (void)setContentCompressionResistancePriority:(UILayoutPriority)priority forAxis:(UILayoutConstraintAxis)axis    

systemLayoutSizeFittingSize

A lot of times, like the UITableviewCell, like the UICollectionViewCell, we need to know what the optimal height is for the subviews inside the current view. Luckily, UIView provides this method for us

systemLayoutSizeFittingSize    

Returns the size of the view that satisfies the constraints it holds.The size of the view that satisfies the constraints it holds. This is to say that the fittest Size of the fittings is returned according to the constraints of the fittings.

The fittings Size options are as follows

const CGSize UILayoutFittingCompressedSize; // The smallest possible size that satisfies the constraint

const CGSize UILayoutFittingExpandedSize; // The largest possible size to satisfy the constraint

Take TableViewCell height calculation as an example

Let’s say we have a Cell like this

Review images

  • Subviews have a Label, top, bottom, left, and right contentViews with a distance of 8

So, how do I return height in heightForRowAtIndexPath?

Method 1: Calculate according to Model

BoundingRectWithSize: Options: Attributes: Context: Calculates the height, and then adds the padding. – Used before iOS 7, this is a clunky, but generic method.

Method two, hand it over to UIKit and calculate the height yourself

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{    

    return UITableViewAutomaticDimension;    

}    

-(CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath{    

    return UITableViewAutomaticDimension;    

}    

Method three, systemLayoutSizeFittingSize can be used to calculate

One thing to note here is that we can only calculate the height if we fix the width, so as you can see from the code below, we have added a width constraint that is less than or equal to the screen width.

Note: When there is an accessoryView or the Table is not full-screen, the width of the cell is not the width of the screen

@interface TableViewController ()    

   

@property (strong,nonatomic)CustomCell * sizeCell;    

   

@end    

   

@implementation TableViewController    

   

– (void)viewDidLoad {    

    [super viewDidLoad];    

    [self.tableView registerNib:[UINib nibWithNibName:@”CustomCell” bundle:nil] forCellReuseIdentifier:@”cell”];    

    self.sizeCell = [[NSBundle mainBundle] loadNibNamed:@”CustomCell” owner:self options:nil].firstObject;    

   

    CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width;    

[self.sizeCell.contentView addConstraint:[NSLayoutConstraint constraintWithItem:self.sizeCell.contentView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationLessThanOrEqual toItem:nil attribute:NSLayoutAttributeWidth Multiplier: 1.0 constant: screenWidth]].

}    

   

-(NSArray *)cellTexts{    

    return @[    

             @”dagudhau”,    

             @”dagudhau”,    

             @”daguddhaughduahhau”,    

             @”dagudhauhduahgudahughduahguhagudhauhfuadhgudhauhuadh”,    

             @”daghduahgudhaguhdauhguhaguhdughauudhau”,    

@”agudhauhduahgudahughduahguhagudhauhfuadhgudhauhuadhdaghduahgudhaguhdauhguhaguhdughauudhauagudhauhduahgudahughduahguhag udhauhfuadhgudhauhuadhdag”,

             @”dagudhau”,    

             @”dagudhau”,    

   

             ];    

}    

#pragma mark – Table view data source    

   

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{    

    self.sizeCell.customLabel.text = [self cellTexts][indexPath.row];    

    CGSize fitSize = [self.sizeCell systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];    

    return fitSize.height;    

}    

– (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {    

    return 1;    

}    

   

– (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {    

    return [self cellTexts].count;    

}    

   

   

– (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {    

    CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:@”cell” forIndexPath:indexPath];    

    cell.customLabel.text = [self cellTexts][indexPath.row];    

    return cell;    

}    

Results the following

iPhone 6 

Review images

iPhone 4s 

Review images


The first time to grasp the latest mobile development related information and technology, please pay attention to mobileHub wechat account (ID: Mobilehub).

Review images