Masonry使用备忘

Author Avatar
XibHe 9月 18, 2016
  • 在其它设备中阅读本文章

记录使用 Masonry 过程中遇到的问题及解决方法,任何看似好用的框架在使用过程中都或多或少的有些瑕疵,解决问题的同时也会引入新的问题。

更新说明

更新记录:

  • 2016 年 09 月,第一版。
  • 2018 年 07 月,补充关于使用Masonry更新坐标的问题。
  • 2019 年 01 月,替换图片访问路径。

使用Masonry的场景

在“我的”界面顶部区域用来展示用户的登录信息,顶部有两种样式的变换,即,由未登录—->已登录。
如图所示,
IMG_3210

其中头像区域是UIImageView,”登录/注册”是UILabel。登录成功后,头像区域会显示由服务器返回的头像地址生成的图片,并且其位置发生变化,不在居中显示,显示”登录/注册”的UILabel变为显示用户昵称,并且坐标位置发生改变。
如图所示,
已登录

我的问题来了,在设置头像和标题位置时使用mas_remakeConstraints设置二者的约束,
代码如图,
代码

当从未登录切换到已登录时,已登录的头像位置会发生改变,变得特别大,不受约束控制。
控制台会报如下错误,
报错

刚开始没有意识到改变UIImageView的约束导致的新旧两种约束冲突造成的问题。在一个小时未解决该问题后,放弃了使用Masonry,改为使用代码做布局。今天,再回头看看这个问题,联想到忽略了什么东西,就打开Masonry文档从头开始仔细往下看,结果就看到了这句话,

Sometimes you need modify existing constraints in order to animate or remove/replace constraints. In Masonry there are a few different approaches to updating constraints.

文档上列举了三种修改现有约束的方法,

  1. References
    你可以引用一个特定约束条件的约束,使表达式的结果分配给一个局部变量或一个类属性。

  2. mas_updateConstraints
    作为一种选择,如果你只是去更新固有的约束值,你可以使用mas_updateConstraints这种便利的方法替换mas_makeConstraints

  3. mas_remakeConstraints
    mas_updateConstraints用于更新一组约束,但要做那些费力的超出超出常量值的约束更新。这时就需要选择mas_remakeConstraints
    mas_remakeConstraints类似于mas_updateConstraints,但它不是更新常量值,当再次为这些已经存在约束的视图设置约束前,它会移除掉该视图上的所有约束。这就让你可以为视图设置新的约束,而不用考虑移除之前已经存在的其他约束。

于是,我使用文档中提到的第三种方法,将所有的mas_makeConstraints换成了mas_remakeConstraints,就解决了约束错乱的问题。

使用Masonry后获取坐标值为0的问题

加载页面头部会留白,如图,

1. 实际上是由于头部切换视图的的 width0 导致。由于使用 Masonry 设置的头部视图,

[self.tabView mas_makeConstraints:^(MASConstraintMaker *make) {
    make.left.top.right.equalTo(self.view);
    make.height.mas_equalTo(kTitleMenuTotalHeight);
}];

2. 在 self.tabView 的初始化类中的set方法里,需要再次设置它的位置,

CGFloat totalTabW = self.width > self.headerArray.count * kTitleMenuItemWidth ? self.headerArray.count * kTitleMenuItemWidth : self.width;
[self.tabView mas_remakeConstraints:^(MASConstraintMaker *make){ 
   make.top.equalTo(self);make.bottom.equalTo(self.dividerLineView. mas_top).offset(-0.5);
   make.centerX.equalTo(self);
   make.width.mas_equalTo(totalTabW);
}];

这里的 self.width 获取为 0,需要在完成 第1步 操作后,添加下面这行代码,即可获取到 self.tabView 的坐标值,

//立即获取到frame
[self.view layoutIfNeeded];

-layoutIfNeeded方法:如果,有需要刷新的标记,立即调用layoutSubviews进行布局(如果没有标记,不会调用layoutSubviews)

layoutIfNeeded方法如其名,UIKit会判断该receiver是否需要layout。根据Apple官方文档,layoutIfNeeded方法应该是这样的,layoutIfNeeded遍历的不是superview链,应该是subviews链。

参考文档

Masonry使用

iOS - layoutSubviews总结

造成这个问题的主要原因是我没有认真看Masonry的文档,文档上说的已经很清楚了。

–EOF–

若无特别说明,本站文章均为原创,转载请保留链接,谢谢