Masonry使用注意篇

作者: 码码乐趣 | 来源:发表于2015-09-11 14:36 被阅读26734次

    Github

    简要

    自动布局最重要的是约束:UI元素间关系的数学表达式。约束包括尺寸、由优先级和阈值管理的相对位置。它们是添加剂,可能导致约束冲突 、约束不足造成布局无法确定 。这两种情况都会产生异常。

    使用前:AutoLayout关于更新的几个方法的区别

    • setNeedsLayout:告知页面需要更新,但是不会立刻开始更新。执行后会立刻调用layoutSubviews。
    • layoutIfNeeded:告知页面布局立刻更新。所以一般都会和setNeedsLayout一起使用。如果希望立刻生成新的frame需要调用此方法,利用这点一般布局动画可以在更新布局后直接使用这个方法让动画生效。
    • layoutSubviews:系统重写布局
    • setNeedsUpdateConstraints:告知需要更新约束,但是不会立刻开始
    • updateConstraintsIfNeeded:告知立刻更新约束
    • updateConstraints:系统更新约束

    使用

    1. 基本使用

    • mas_makeConstraints:添加约束

    • mas_updateConstraints:更新约束、亦可添加新约束

    • mas_remakeConstraints:重置之前的约束

    • multipler属性表示约束值为约束对象的乘因数, dividedBy属性表示约束值为约束对象的除因数,可用于设置view的宽高比

    // 进行屏幕的适配的时候,往往需要根据屏幕宽度来适配一个相应的高度,在此推荐使用如下约束的方式来进行控件的适配
    [self.topView addSubview:self.topInnerView];
    [self.topInnerView mas_makeConstraints:^(MASConstraintMaker *make) {
          make.height.equalTo(self.topView.mas_height).dividedBy(3);
          make.width.and.height.lessThanOrEqualTo(self.topView);
          make.width.and.height.equalTo(self.topView).with.priorityLow();
          make.center.equalTo(self.topView);
    }];
    
    • priorityLow()设置约束优先级
    • #define MAS_SHORTHAND_GLOBALS使用全局宏定义,可以使equalTo等效于mas_equalTo
    • #define MAS_SHORTHAND使用全局宏定义, 可以在调用masonry方法的时候不使用mas_前缀
    // 这里注意到一个地方,就是当使用了这个全局宏定义之后,发现可以有个类`NSArray+MASAdditions.h`,看了之后发现可以
    self.buttonViews = @[ raiseButton, lowerButton, centerButton ];
    // 之后可以在updateConstraints 方法中
    - (void)updateConstraints {
       [self.buttonViews updateConstraints:^(MASConstraintMaker *make) {
            make.baseline.equalTo(self.mas_centerY).with.offset(self.offset);
        }];
        [super updateConstraints];  
    }
    
    • 动态修改视图约束:
    // 创建视图约束
    [blueView mas_makeConstraints:^(MASConstraintMaker *make) {
            self.animatableConstraint = make.edges.equalTo(superview).insets(paddingInsets).priorityLow();
    ]];
    // 更改约束 (另一处方法中)
    UIEdgeInsets paddingInsets = UIEdgeInsetsMake(padding, padding, padding, padding);
    self.animatableConstraint.insets = paddingInsets;
    [self layoutIfNeeded];
    
    • debug模式:
    // 对某个view添加key值
    greenView.mas_key = @"greenView";
    // 或者如下顺序
    MASAttachKeys(greenView, redView, blueView, superview);
    // 同样的对每条约束亦可以添加key
    make.height.greaterThanOrEqualTo(@5000).key(@"ConstantConstraint");
    
    • preferredMaxLayoutWidth: 多行label的约束问题
    // 已经确认好了位置
    // 在layoutSubviews中确认label的preferredMaxLayoutWidth值
    - (void)layoutSubviews {
        [super layoutSubviews];
        // 你必须在 [super layoutSubviews] 调用之后,longLabel的frame有值之后设置preferredMaxLayoutWidth
        self.longLabel.preferredMaxLayoutWidth = self.frame.size.width-100;
        // 设置preferredLayoutWidth后,需要重新布局
        [super layoutSubviews];
    }
    
    • scrollView使用约束的问题:原理通过一个contentView来约束scrollView的contentSize大小,也就是说以子控件的约束条件,来控制父视图的大小
    // 1. 控制scrollView大小(显示区域)
    [self.scrollView makeConstraints:^(MASConstraintMaker *make) {
         make.edges.equalTo(self.view);
    }];
    // 2. 添加一个contentView到scrollView,并且添加好约束条件
    [contentView makeConstraints:^(MASConstraintMaker *make) {
         make.edges.equalTo(self.scrollView);
         // 注意到此处的宽度约束条件,这个宽度的约束条件是比添加项
         make.width.equalTo(self.scrollView);
    }];
    // 3. 对contentView的子控件做好约束,达到可以控制contentView的大小
    
    • 新方法:2个或2个以上的控件等间隔排序
    /**
     *  多个控件固定间隔的等间隔排列,变化的是控件的长度或者宽度值
     *
     *  @param axisType        轴线方向
     *  @param fixedSpacing    间隔大小
     *  @param leadSpacing     头部间隔
     *  @param tailSpacing     尾部间隔
     */
    - (void)mas_distributeViewsAlongAxis:(MASAxisType)axisType 
                        withFixedSpacing:(CGFloat)fixedSpacing l
                              eadSpacing:(CGFloat)leadSpacing 
                             tailSpacing:(CGFloat)tailSpacing;
    
    /**
     *  多个固定大小的控件的等间隔排列,变化的是间隔的空隙
     *
     *  @param axisType        轴线方向
     *  @param fixedItemLength 每个控件的固定长度或者宽度值
     *  @param leadSpacing     头部间隔
     *  @param tailSpacing     尾部间隔
     */
    - (void)mas_distributeViewsAlongAxis:(MASAxisType)axisType 
                     withFixedItemLength:(CGFloat)fixedItemLength 
                             leadSpacing:(CGFloat)leadSpacing 
                             tailSpacing:(CGFloat)tailSpacing;
    

    使用方法很简单,因为它是NSArray的类扩展:

    //  创建水平排列图标 arr中放置了2个或连个以上的初始化后的控件
    //  alongAxis 轴线方向   固定间隔     头部间隔      尾部间隔
    [arr mas_distributeViewsAlongAxis:MASAxisTypeHorizontal withFixedSpacing:20 leadSpacing:5 tailSpacing:5];
    [arr mas_makeConstraints:^(MASConstraintMaker *make) {
           make.top.equalTo(@60);
           make.height.equalTo(@60);
    }];
    

    2. 注意事项

    • 约束视图对象只有在被addSubview之后,才能给视图添加约束
    • 当你的所有约束都在 updateConstraints 内调用的时候,你就需要在此调用此方法,因为 updateConstraints方法是需要触发的
    // 调用在view 内部,而不是viewcontroller
    + (BOOL)requiresConstraintBasedLayout {
        return YES;
    }
    
    /**
     *  苹果推荐 约束 增加和修改 放在此方法种
     */
    - (void)updateConstraints {
        [self.growingButton updateConstraints:^(MASConstraintMaker *make) {
            make.center.equalTo(self);
            make.width.equalTo(@(self.buttonSize.width)).priorityLow();
            make.height.equalTo(@(self.buttonSize.height)).priorityLow();
            make.width.lessThanOrEqualTo(self);
            make.height.lessThanOrEqualTo(self);
        }];
        //最后记得回调super方法
        [super updateConstraints];
    }
    
    • 如果想要约束变换之后实现动画效果,则需要执行如下操作
    // 通知需要更新约束,但是不立即执行
    [self setNeedsUpdateConstraints];
    // 立即更新约束,以执行动态变换
    // update constraints now so we can animate the change
    [self updateConstraintsIfNeeded];
    // 执行动画效果, 设置动画时间
    [UIView animateWithDuration:0.4 animations:^{
         [self layoutIfNeeded];
    }];
    

    相关文章

      网友评论

      • 世界的一缕曙光:请问cell中的约束代码写在layoutSubviews中合适吗?或者说应该写在哪个位置。在cell有固定高度和非固定高度两种情况下。
        d428c82fffac:如果布局始终不变的话就没必要写到layoutSubViews,有些情况下这个方法不会被调用的
      • 风车大战骑士: 请问下,我用masonry更新约束提示冲突。
        [_itemImgView mas_makeConstraints:^(MASConstraintMaker *make) {

        make.top.equalTo(_bgView).offset(5 * WIDTH_MULTIPLE);
        make.left.equalTo(self).offset(10 * WIDTH_MULTIPLE);
        make.bottom.equalTo(self).offset(-5 * WIDTH_MULTIPLE);
        make.width.mas_equalTo(70 * WIDTH_MULTIPLE);
        }];

        [_itemImgView mas_updateConstraints:^(MASConstraintMaker *make) {

        make.left.equalTo(self).offset(35 * WIDTH_MULTIPLE);
        }];
        这个是什么问题,也是在相对对一个更改的啊
        d428c82fffac:约束冲突,加一个优先级试试,就是那个priority这个东西
        kingkong1221:代码没问题啊 具体冲突提示是什么
      • 童话镇里蜿蜒的河:mas_distributeViewsAlongAxis 一定是均分的吗? 如果我的控件大小不一,在数组中,我要怎么去布局。
        WellCheng:control 大小不一样,但是想要 control 之间的距离不一样,可以修改方法的内部实现,不要设置 width,然后在外面分别设置每个 control 的width 约束,如果 control 是有 intrinsic content size,那么就不用管了
      • f170d29955a5:"使用方法很简单,因为它是NSArray的类扩展:"这句话下面的“ makeConstraints”前面落下mas_了
        码码乐趣:谢谢指出,已更正
      • championfu:想问一句,子视图的top或bottom或centerY在俯视图的1/5初,这种约束,该怎么添加(宽度煤比例关系)
      • Cocoa丶:为什么在window上用masonry布局会找不到当前视图的superview
        d428c82fffac:为啥布局要写在window上,一般不都在view上吗
      • a637237315f9:感谢分享
      • 热血足球2016:请问下什么时候用 equalTo 什么时候用mas_equalTo make.right.equalTo(weakSelf.view).offset(-margin);
        make.height.mas_equalTo(view1);
        lanmoyingsheng:@OnceChange :+1::+1:
        OnceChange:@lanmoyingsheng 并不完全一样。在没有添加 MAS_SHORTHAND 情况下。equalTo 只能使用对象使用,mas_equalTo 可以使用对象,也可以使用 基本数据类型。
        lanmoyingsheng:这两个一样
      • 江户川_乱步:熟练以后布局问题 so easy。
      • e9014c2d3b7d:感谢分享!!!! 正好用到.
      • 阳关三叠:很好。

      本文标题:Masonry使用注意篇

      本文链接:https://www.haomeiwen.com/subject/wzspcttx.html