IOS masonry constraint related

Time:2022-5-17

Masonry code parsing

Control size adaptation

scrollView

Goal: let the compiler automatically calculate the height of contentsize.
Implementation: complete the internal top-down constraints of containerview.

Steps:

  • 1> External constraints
UIScrollView *scrollView = [[UIScrollView alloc] init];
scrollView.backgroundColor = UIColor.blueColor;
scrollView.showsVerticalScrollIndicator = NO;
scrollView.showsHorizontalScrollIndicator = NO;
//Scrollview turns on scrolling by default
scrollView.alwaysBounceVertical = YES;
[self.view addSubview:scrollView];
[scrollView mas_makeConstraints:^(MASConstraintMaker *make) {
    make.edges.equalTo(self.view);
}];
UIView *containerView = [[UIView alloc] init];
[scrollView addSubview:containerView];
[containerView mas_makeConstraints:^(MASConstraintMaker *make) {
    make.edges.equalTo(scrollView);
    //Note: the compiler should calculate automatically, so height cannot be set here!!!
    make.width.equalTo(scrollView);
}];
_containerView = containerView;
//Setting contentsize is optional.
// scrollView.contentSize = containerView.bounds.size;
  • 2> Let the compiler calculate the height of containerview
//1 > > internal constraints are from top to bottom, allowing the compiler to calculate the height by itself
[lastView mas_makeConstraints:^(MASConstraintMaker *make) {
    make.bottom.equalTo(containerView).offset(-20);
}];

//Or 2 > > the height of the given containerview
[containerView mas_makeConstraints:^(MASConstraintMaker *make) {
    make.height.mas_equalTo(300);
}];

View

Goal: let the compiler automatically calculate the height of the parent control.
Implementation: (the same as tableviewcell height adaptation principle) the external constraints are carried out from top to bottom. If the compiler can calculate the final height, it can help us complete the height adaptation of the parent control.

UILabel *content_lb = [UILabel new];
[content_lb setText:@".........."];
content_lb.numberOfLines = 0;
[parentView addSubview:content_lb];
[content_lb mas_makeConstraints:^(MASConstraintMaker *make) {
    make.leading.mas_offset(5);
    make.trailing.mas_offset(-5);
    make.top.equalTo(head_iv.mas_bottom).offset(20);
    make.bottom.mas_equalTo(-21);
}];
   
[parentView mas_makeConstraints:^(MASConstraintMaker *make) {
    make.top.leading.trailing.equalTo(self.view);
}];

Constraint priority

Constraint priority: if two constraints conflict under certain circumstances, the constraint with lower priority will not be executed by default.

The priority of constraints with different conditions for the same attribute

1> Requirements:
Product Name: name with variable length (rich text), as shown in Figure 1
Product details: desc with variable length (rich text), as shown in Figure 2
Capacity label: capacity:

  • In the case of less name and desc content, it is on the same line with the bottom of the picture, as shown in Figure 2
  • When there are many contents of name and DESC, it is 15 units away from DESC, as shown in Figure 3
IOS masonry constraint related

Figure 1

IOS masonry constraint related

Figure 2

IOS masonry constraint related

Figure 3

2> Constraint implementation

[name_lb mas_makeConstraints:^(MASConstraintMaker *make) {
    make.top.equalTo(imageView);
    make.leading.equalTo(imageView.mas_trailing).offset(20 *MKScale);
    make.trailing.mas_offset(-16.5 *MKScale);
}];
   
[desc_lb mas_makeConstraints:^(MASConstraintMaker *make) {
    make.leading.trailing.equalTo(name_lb);
    make.top.equalTo(name_lb.mas_bottom).offset(5 *MKScale);
}];
[capacity_lb mas_makeConstraints:^(MASConstraintMaker *make) {
    make.leading.equalTo(name_lb);
    make.bottom.mas_equalTo(-20 *MKScale);
       
    make.top.greaterThanOrEqualTo(desc_lb.mas_bottom).offset(15 *MKScale);
    make.bottom.equalTo(product_iv).priority(500);
}];

3> Scene analysis

IOS masonry constraint related

Key points:

  • name_ LB and desc_ LB height is not constrained because it changes dynamically, so let the compiler handle it by itself.

  • capacity_ LB meets:

    • Constraint a: the difference between the bottom and the parent view bottom is 20.
    • Constraint B: top and desc_ LB bottom distance > = 15. (greaterthanorequalto generates a value that is uncertain in some cases. Default priority: 1000)
    • Constraint C: bottom and ImageView levels. (manually set low priority: 500)
  • If the dynamic area is large, constraint B will specify space as 15. This conflicts with constraint C. C does not take effect because of its low priority.

  • If the dynamic area is not large, the space will be stretched so that the space is an uncertain value greater than 15. At this time, there is no constraint conflict and constraint C will be satisfied.

In IOS 11, the cell layout can be adapted automatically without manually setting rowheight and restimatedrowheight. (but not in IOS 10)
tableView.rowHeight = UITableViewAutomaticDimension;
tableView.estimatedRowHeight = 200;

Control extrusion and stretching problems

IOS masonry constraint related

Scene: there are two controls redview and label in stackview. Setting the width of stackview manually will stretch one of the child controls.
How to control which control to stretch:
Set the priority of the corresponding constraint. The low priority will change.

[imgView mas_makeConstraints:^(MASConstraintMaker *make) {
    make. width. mas_ equalTo(30). priority(10); //  ImageView has low priority and will be stretched or set directly priorityLow()
    make.height.mas_equalTo(20);
}];

[label mas_makeConstraints:^(MASConstraintMaker *make) {
    make. width. mas_ equalTo(width). priority(100); //  Or set it directly Priorityhigh() needs to write out the constraints, but it cannot be adaptive
}];

Dynamic update constraint

Weak reference constraint (recommended)

It is equivalent to re creating constraints (not all, but the constraints you want to update). It is applicable to all situations and can be updated immediately.

@property (nonatomic, weak) MASConstraint *constraint;

[self.nameLabel mas_makeConstraints:^(MASConstraintMaker *make) {
    self.constraint = make.right.equalTo(self).priorityLow();
}];

- (void)changePriority:(BOOL)isHigh {
    //Invalidate the constraint (uninstall is called internally and removed from the constraint group. Since the current constraint is weakly referenced and is not strongly referenced by other pointers, it will be recycled by the system)
    [self.constraint uninstall];

    //Re create constraints (mas_updateconstraints will add the constraints in the block to the constraint group and take effect)
    [self.nameLabel mas_updateConstraints:^(MASConstraintMaker *make) {
        if (isHigh) {
            self.constraint = make.right.equalTo(self).priorityHigh();
        } else {
            self.constraint = make.right.equalTo(self).priorityLow();
        }
    }];
    //Refresh layout
    [self layoutIfNeeded];
}

Strong reference constraint (OC not recommended, swift applicable)

If it is modified immediately after initialization (within the same runloop loop), there will be no change. It is applicable to updating later after initialization.

OC (not recommended)

@property (nonatomic, strong) MASConstraint *constraint;

[self.nameLabel mas_makeConstraints:^(MASConstraintMaker *make) {
    self.constraint = make.right.equalTo(self).priorityLow();
}];

- (void)changePriority:(BOOL)isHigh {
    //Invalidate the constraint (uninstall is called internally and removed from the constraint group)
    [self.constraint deactivate]; 

    //Reset priority
    if (isHigh) {
        self.constraint.priorityHigh();
    } else {
        self.constraint.priorityLow();
    }
    //Make the constraint effective (call install internally and add it back to the constraint group)
    [self.constraint activate]; 

    //Refresh layout
    [self layoutIfNeeded];
}

Swift (applicable)

var bottomConstraint: Constraint?

view.snp.makeConstraints { (make) in
  // ...
  bottomConstraint = make. bottom. equalToSuperview(). Constraint // reference of constraint
}
//Under certain conditions, it will fail and the constraint will be reset
bottomConstraint?.deactivate()
bottomConstraint = nil

Other skills

Equidistant constraint

/**
 *  distribute with fixed spacing
 *
 *  @param axisType     which axis to distribute items along
 *  @param fixedSpacing the spacing between each item
 *  @param leadSpacing  the spacing before the first item and the container
 *  @param tailSpacing  the spacing after the last item and the container
 */
- (void)mas_distributeViewsAlongAxis:(MASAxisType)axisType withFixedSpacing:(CGFloat)fixedSpacing leadSpacing:(CGFloat)leadSpacing tailSpacing:(CGFloat)tailSpacing;
/**
 *  distribute with fixed item size
 *
 *  @param axisType        which axis to distribute items along
 *  @param fixedItemLength the fixed length of each item
 *  @param leadSpacing     the spacing before the first item and the container
 *  @param tailSpacing     the spacing after the last item and the container
 */
- (void)mas_distributeViewsAlongAxis:(MASAxisType)axisType withFixedItemLength:(CGFloat)fixedItemLength leadSpacing:(CGFloat)leadSpacing tailSpacing:(CGFloat)tailSpacing;
//Ex:
NSMutableArray <UIView *> *views = [NSMutableArray array];
for (int i = 0; i < info.count; i++) {
    UIView *view = [self createViewWithInfo:info[i]];
    [views addObject:view];
}
//Constraint left and right, spacing
[views mas_distributeViewsAlongAxis:MASAxisTypeHorizontal withFixedSpacing:18 *MKScale leadSpacing:0 tailSpacing:0];
//Constraint up and down
[views mas_makeConstraints:^(MASConstraintMaker *make) {
    make.top.bottom.equalTo(self.pwdView);
}];

Batch setting constraints

Suppose there are three views: view1, view2 and view3. We want their width and height to be equal to cgsizemake (100, 50). We can set them up in batches

NSValue *sizeValue = [NSValue valueWithCGSize:CGSizeMake(100, 50)];
[@[view1,view2,view3] mas_makeConstraints:^(MASConstraintMaker *make) {
    make.size.equalTo(sizeValue);
}];

Because we also need to set the top, left and other position constraints of the view. Is that possible in the setting position_ How to batch set the width and height in makeconstraints? Actually, it is possible!

[view1 mas_makeConstraints:^(MASConstraintMaker *make) {
    (void)make.top.left;
    make.size.equalTo(@[view2,view3,sizeValue]);
}];

mas_key

When constraint conflicts occur, we often worry about not finding which view is in conflict. At this time, we can set the key of the view to clearly know which view is in conflict

view1.mas_key = @“view1”;
view2.mas_key = @“view2”;

//Mason provides the macro masattachkeys for batch setting, which can be set in one sentence of code:
MASAttachKeys(view1,view2);

Do not use MAS prefix (not recommended)

Plus MAS_ The prefix is mainly used when extending the system class to avoid conflict with the original class, which is recommended by apple. But for now, even without MAS_ Prefix, there will be no problem. So Mason offers no MAS_ The prefix method only requires you to define a few macros.

1. MAS_SHORTHAND
Define MAS_ After the shortcut macro. You can use uiview without MAS in nsarray_ Prefix makeconstraints, updateconstraints, remakeconstraints. And without MAS in uiview_ Prefix attribute.
2. MAS_SHORTHAND_GLOBALS
The default equalto method only accepts objects of type ID. Sometimes we want to pass in a cgfloat, cgsize, uiedgeinsets, etc. It also needs to be converted into nsvalue object, which is troublesome. Mason also considered this situation. Only MAS needs to be defined_ SHORTHAND_ Globals macro. You can pass in the base type directly to equalto. The masonry is automatically converted to an nsvalue object

Problems encountered

UI proofreading is inconsistent with the design draft

IOS masonry constraint related

Phenomenon: Although the font and spacing are set according to the blue lake annotation, the effect is inconsistent.
Reason: the inner margin of font cannot be considered in blue lake annotation
Solution: set the label height to font size + 2(+ 2 is because if the font size and height are 1:1, some characters will not be displayed completely, for example: G J), because the addition of two positions will be allocated to one pixel above and one pixel below the original label, the original upper and lower constraints should be modified to – 1.

The control of Xib cannot get the correct width and height

Phenomenon: sometimes, the child control needs to calculate the width and height according to the parent control. If it is a control (cell) generated by Xib, the code takes the width and height to obtain the width and height displayed in the graphical interface of Xib

IOS masonry constraint related

For example, pull the cell width to 300, and tableview width = screen width. At this time, under the 375 screen, the cell width is 375, but the value is still 300

Solution: for the control that needs to calculate the width and height, its parent view is created in pure code, and Xib is not used as much as possible