ios环境第三方库

【Masonry】详解以及三种约束方法与注意事项

2021-10-13  本文已影响0人  物非0人非

Masonry本质

Masonry就是对系统AutoLayout进行的封装,包括里面很多的API,都是对系统API进行了一次二次包装。

typedef NS_OPTIONS(NSInteger, MASAttribute) {
    MASAttributeLeft = 1 << NSLayoutAttributeLeft,
    MASAttributeRight = 1 << NSLayoutAttributeRight,
    MASAttributeTop = 1 << NSLayoutAttributeTop,
    MASAttributeBottom = 1 << NSLayoutAttributeBottom,
    MASAttributeLeading = 1 << NSLayoutAttributeLeading,
    MASAttributeTrailing = 1 << NSLayoutAttributeTrailing,
    MASAttributeWidth = 1 << NSLayoutAttributeWidth,
    MASAttributeHeight = 1 << NSLayoutAttributeHeight,
    MASAttributeCenterX = 1 << NSLayoutAttributeCenterX,
    MASAttributeCenterY = 1 << NSLayoutAttributeCenterY,
    MASAttributeBaseline = 1 << NSLayoutAttributeBaseline,
};

一:Masonry基础API

mas_makeConstraints()    添加约束
mas_remakeConstraints()  移除之前的约束,重新添加新的约束
mas_updateConstraints()  更新约束,写哪条更新哪条,其他约束不变

equalTo()       参数是对象类型,一般是视图对象或者mas_width这样的坐标系对象
mas_equalTo()   和上面功能相同,参数可以传递基础数据类型对象,可以理解为比上面的API更强大

width()         用来表示宽度,例如代表view的宽度
mas_width()     用来获取宽度的值。和上面的区别在于,一个代表某个坐标系对象,一个用来获取坐标系对象的值

二:Masonry更新约束和布局

- (void)updateConstraintsIfNeeded  调用此方法,如果有标记为需要重新布局的约束,则立即进行重新布局,内部会调用updateConstraints方法
- (void)updateConstraints          重写此方法,内部实现自定义布局过程
- (BOOL)needsUpdateConstraints     当前是否需要重新布局,内部会判断当前有没有被标记的约束
- (void)setNeedsUpdateConstraints  标记需要进行重新布局

三: 设置内边距

方法1:offset()方法,此法繁琐

/** 
 设置yellow视图和self.view等大,并且有10的内边距。
 注意根据UIView的坐标系,下面right和bottom进行了取反。所以不能写成下面这样,否则right、bottom这两个方向会出现问题。
 make.edges.equalTo(self.view).with.offset(10);
 
 除了下面例子中的offset()方法,还有针对不同坐标系的centerOffset()、sizeOffset()、valueOffset()之类的方法。
 */
[self.yellowView mas_makeConstraints:^(MASConstraintMaker *make) {
    make.left.equalTo(self.view).with.offset(10);
    make.top.equalTo(self.view).with.offset(10);
    make.right.equalTo(self.view).with.offset(-10);
    make.bottom.equalTo(self.view).with.offset(-10);
}];

方法2:通过insets简化设置内边距的方式,,此法简单

// 下面的方法和上面例子等价,区别在于使用insets()方法。
[self.blueView mas_makeConstraints:^(MASConstraintMaker *make) {
    // 下、右不需要写负号,insets方法中已经为我们做了取反的操作了。
    make.edges.equalTo(self.view).with.insets(UIEdgeInsetsMake(10, 10, 10, 10));
}];

四: mas_makeConstraintsmas_remakeConstraintsmas_updateConstraints 区别

mas_makeConstraints()    添加约束
mas_remakeConstraints()  移除之前的约束,重新添加新的约束
mas_updateConstraints()  更新约束,写哪条更新哪条,其他约束不变

1: mas_makeConstraints
特点:只负责新增约束

[testView mas_makeConstraints:^(MASConstraintMaker *make) { 
   make.leading.equalTo(view1. mas_top).offset(10); 
   make.bottom.equalTo(view2.mas_bottom).offset(-2); 
   make.height.mas_equalTo(70); 
   make.width.mas_equalTo(50); 
}];

2: mas_remakeConstraints
特点:会清除当前对象之前的所有约束,仅保留最新的约束

# 会清除原来的约束,保留新的约束 
[testView mas_remakeConstraints :^(MASConstraintMaker *make) { 
   make.bottom.equalTo(view3.mas_top).offset(-10); 
   make.centerX.equalTo(view4.mas_centerX); 
   make.height.mas_equalTo(70); 
   make.width.mas_equalTo(50); 
}];

3: mas_updateConstraints
特点:更新对象的约束

注意: 同一个对象 使用mas_updateConstraints 一定要保证block中要更新的元素是其使用mas_makeConstraints设置的约束

1,正确的示例:如下就是正确的,则不会出现约束冲突问题

[testView mas_updateConstraints:^(MASConstraintMaker *make) {
   //必须是 同一参照对象(都是以view1)同一参照属性(都是以view1的mas_top)  
      make.bottom.equalTo(view1.mas_top).offset(-60); 
   
}];

2,错误的示例:但是下面的就不对了,就会出现约束冲突 在iOS 7 及其以下会出现由于约束冲突出现的崩溃

[testView mas_updateConstraints:^(MASConstraintMaker *make) { 
    //原因1:不同一参照对象 (原来是view1 现在是view2) 
    //原因2 testView 在 mas_makeConstraints中没有设置 centerX 所以无法更新 
    //解决办法:  使用 mas_remakeConstraints 清除原来的约束,重新设置约束; 
   make.bottom.equalTo(view2.mas_top).offset(-10); 
   make.centerX.equalTo(view4.mas_centerX); 
}];

例子2: mas_updateConstraints使用

// 设置greenView的center和size,这样就可以达到简单进行约束的目的
[self.greenView mas_makeConstraints:^(MASConstraintMaker *make) {
    make.center.equalTo(self.view);
    // 这里通过mas_equalTo给size设置了基础数据类型的参数,参数为CGSize的结构体
    make.size.mas_equalTo(CGSizeMake(300, 300));
}];

// 为了更清楚的看出约束变化的效果,在显示两秒后更新约束。
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    // 指定更新size,其他约束不变。
    [self.greenView mas_updateConstraints:^(MASConstraintMaker *make) {
        make.size.mas_equalTo(CGSizeMake(100, 100));
    }];
});

五:大于等于小于等于某个值的约束

[self.textLabel mas_makeConstraints:^(MASConstraintMaker *make) {
    make.center.equalTo(self.view);
    // 设置宽度小于等于200
    make.width.lessThanOrEqualTo(@200);
    // 设置高度大于等于10
    make.height.greaterThanOrEqualTo(@(10));
}];

self.textLabel.text = @"这是测试的字符串。能看到1、2、3个步骤,第一步当然是上传照片了,要上传正面近照哦。上传后,网站会自动识别你的面部,如果觉得识别的不准,你还可以手动修改一下。左边可以看到16项修改参数,最上面是整体修改,你也可以根据自己的意愿单独修改某项,将鼠标放到选项上面,右边的预览图会显示相应的位置。";

textLabel只需要设置一个属性即可

self.textLabel.numberOfLines = 0;

使用基础数据类型当做参数

/** 
 如果想使用基础数据类型当做参数,Masonry为我们提供了"mas_xx"格式的宏定义。
 这些宏定义会将传入的基础数据类型转换为NSNumber类型,这个过程叫做封箱(Auto Boxing)。

 "mas_xx"开头的宏定义,内部都是通过MASBoxValue()函数实现的。
 这样的宏定义主要有四个,分别是mas_equalTo()、mas_offset()和大于等于、小于等于四个。
 */
[self.redView mas_makeConstraints:^(MASConstraintMaker *make) {
    make.center.equalTo(self.view);
    make.width.mas_equalTo(100);
    make.height.mas_equalTo(100);
}];

设置约束优先级

/** 
 Masonry为我们提供了三个默认的方法,priorityLow()、priorityMedium()、priorityHigh(),这三个方法内部对应着不同的默认优先级。
 除了这三个方法,我们也可以自己设置优先级的值,可以通过priority()方法来设置。
 */
[self.redView mas_makeConstraints:^(MASConstraintMaker *make) {
    make.center.equalTo(self.view);
    make.width.equalTo(self.view).priorityLow();
    make.width.mas_equalTo(20).priorityHigh();
    make.height.equalTo(self.view).priority(200);
    make.height.mas_equalTo(100).priority(1000);
}];
Masonry也帮我们定义好了一些默认的优先级常量,分别对应着不同的数值,优先级最大数值是1000。
static const MASLayoutPriority MASLayoutPriorityRequired = UILayoutPriorityRequired;
static const MASLayoutPriority MASLayoutPriorityDefaultHigh = UILayoutPriorityDefaultHigh;
static const MASLayoutPriority MASLayoutPriorityDefaultMedium = 500;
static const MASLayoutPriority MASLayoutPriorityDefaultLow = UILayoutPriorityDefaultLow;
static const MASLayoutPriority MASLayoutPriorityFittingSizeLevel = UILayoutPriorityFittingSizeLevel;

设置约束比例

// 设置当前约束值乘以多少,例如这个例子是redView的宽度是self.view宽度的0.2倍。
[self.redView mas_makeConstraints:^(MASConstraintMaker *make) {
    make.center.equalTo(self.view);
    make.height.mas_equalTo(30);
    make.width.equalTo(self.view).multipliedBy(0.2);
}];

子视图等高/等宽练习

     /**
     下面的例子是通过给equalTo()方法传入一个数组,设置数组中子视图及当前make对应的视图之间等高。
     
     需要注意的是,下面block中设置边距的时候,应该用insets来设置,而不是用offset。
     因为用offset设置right和bottom的边距时,这两个值应该是负数,所以如果通过offset来统一设置值会有问题。
     */
    
    CGFloat padding = 10;
    
    UIView *redView = [[UIView alloc]init];
    redView.backgroundColor = [UIColor redColor];
    [self.view addSubview:redView];
    
    UIView *blueView = [[UIView alloc]init];
    blueView.backgroundColor = [UIColor blueColor];
    [self.view addSubview:blueView];
    
    UIView *yellowView = [[UIView alloc]init];
    yellowView.backgroundColor = [UIColor yellowColor];
    [self.view addSubview:yellowView];

    /**********  等高   ***********/
    [redView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.right.top.equalTo(self.view).insets(UIEdgeInsetsMake(padding, padding, 0, padding));
        make.bottom.equalTo(blueView.mas_top).offset(-padding);
    }];
    [blueView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.right.equalTo(self.view).insets(UIEdgeInsetsMake(0, padding, 0, padding));
        make.bottom.equalTo(yellowView.mas_top).offset(-padding);
    }];

    /**
     下面设置make.height的数组是关键,通过这个数组可以设置这三个视图高度相等。其他例如宽度之类的,也是类似的方式。
     */
    [yellowView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.right.bottom.equalTo(self.view).insets(UIEdgeInsetsMake(0, padding, padding, padding));
        make.height.equalTo(@[blueView, redView]);
    }];

    /**********  等宽   ***********/
    [redView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.left.bottom.equalTo(self.view).insets(UIEdgeInsetsMake(padding, padding, padding, 0));
       //这里两行 至关重要
        make.right.equalTo(blueView.mas_left).offset(-padding);
    }];
    [blueView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.bottom.equalTo(self.view).insets(UIEdgeInsetsMake(padding, 0, padding, 0));
        make.right.equalTo(yellowView.mas_left).offset(-padding);
    }];
    [yellowView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.bottom.right.equalTo(self.view).insets(UIEdgeInsetsMake(padding, 0, padding, padding));
        make.width.equalTo(@[redView, blueView]);
    }];
image.png
image.png

子视图垂直居中练习

    CGFloat padding = 10;
    
    UIView *redView = [[UIView alloc]init];
    redView.backgroundColor = [UIColor redColor];
    [self.view addSubview:redView];
    
    UIView *blueView = [[UIView alloc]init];
    blueView.backgroundColor = [UIColor blueColor];
    [self.view addSubview:blueView];
    
    [redView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.centerY.equalTo(self.view);
        make.left.equalTo(self.view).mas_offset(padding);
        make.right.equalTo(blueView.mas_left).mas_offset(-padding);
        //make.width.equalTo(blueView);
        make.height.mas_equalTo(150);
    }];
    
    [blueView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.centerY.equalTo(self.view);
        make.right.equalTo(self.view).mas_offset(-padding);
        make.width.equalTo(redView);
        make.height.mas_equalTo(150);
    }];
上一篇下一篇

猜你喜欢

热点阅读