Masonry动态布局的解决方案

这篇文章不是用来介绍如何通过Masonry来实现auto layout的,并且是假设读者已经对使用 Masonry 有一定的经验了。

以下面这个页面为例,页面元素的基本布局是 **self.view ****UIScrollView ******UIView (containerView) ********UILabel, UITextField, UIButton, UITableView, CustomView

其中部分元素是动态的:基于Model中的数据不同,Related AC下面有时候会显示一排label的描述,如果没有对应数据就不显示。同样地,Expense List下面也有一个UITableView,如下图,区别主要在于页面元素之间的间隔会发生变化。另外,在这个页面编辑的过程中,如果用户点击对应属性后面的添加按钮,Related AC和Expense List下面对应的数据都会发生变化。

Masonry动态布局的解决方案_第1张图片

如何刷新才能让页面中的view基于数据重新排版?

为了说明问题,上面这个页面只是一个简单的示例,但是我们需要找到的是一种通用的解决方案。

有两个方法:

每次需要刷新页面时,先把scrollView的content offset记下来,同时也把所有的和数据相关的view的值都保存到Controller中的新property中,然后删除所(!)有(!)self.view中的subviews,然后重新创建新的view对象,这个时候重新创建(mas_makeConstraint)所有view的约束,把之前保存的所有数据全部都赋值给新view。

这种方案不好的地方在于完全把ViewController中的重要view和对应view的数据显式分开了,需要额外注意每次在“刷新”UI的时候把所有的view及其数据做好对应保存。

如果某个view还存在跟随数据变化的同时和有其他属性变化,在“刷新”UI的时候还需要做一些额外的临时状态保存处理。

让页面上所有的元素在整个ViewController的生命周期中只创建一次,然后把所有需要在“刷新”时需要做位置变换的view(这至少包含了所有会发生数据变化的view)全部创建为controller类的property,数据发生变化后“刷新”UI时,只需要remake所有相关的view’s constraints。

相比之下这样做的好处是没有把view和它的数据及属性分开,在controller中更清晰一些。

我虽然已经用Masonry来完成auto layout很久了,但是updateConstraint和remakeConstraint还是用得不多的。这个方法中就大量用了remake来更新UI页面元素位置。

UIViewController中有两个需重载的重要方法,- (void)viewDidLayoutSubviews和- (void)updateViewConstraints,代码实现如下。


Masonry动态布局的解决方案_第2张图片

为了尽量把make和remake同样的constraint放到同一个实现中,所以我又额外写了一个针对Masonry的两个helper方法:


Masonry动态布局的解决方案_第3张图片

就这样,所有UIView的constraint都在- (void)updateMASLayout:方法中实现。这个实现目前我在iOS 9/Xcode 7中演示成功。

至于到底选择那种方案来实现类这种动态页面的布局,个人认为还是需要部分参考项目需求,如果有太多view属性也需要跟随着数据发生变化的话,建议还是参考第二种。

关于针对UIScrollView的contentSize在autolayout中的适配问题,下面是两个参考。

Masonry 开源项目有一个关于UIScrollVIew的示例,是基于纯代码布局的解决办法。

AutoLayout深入浅出三[相遇Scrollview] , 如果是storyboard/xib实现的布局,可以看看这篇文章提供的解决办法。

转载至http://www.07net01.com/2015/11/957821.html

你可能感兴趣的:(Masonry动态布局的解决方案)