1.为什么autolayout?
尽管autolayout推出的时间已经不短了(自ios6以后就可以使用),但是在很长的时间段里,有很多人都不太了它,包括我自己,因为以前手写frame的时代我们已经太过习惯,而且以前也有不少吐槽autolayout的文章,包括性能,API等等一些方面,加上以前的iPhone的屏幕只有3.5~4inch两种,所以很多人都忽略了这项技术。不过有了iPhone6及plus以后,这样的问题就凸显了,手写frame的习惯让我痛苦不堪,想想自己写了一大堆和业务逻辑无关的布局代码就头疼,于是我也开始意识到autolayout是不得不用的了。
2.autolayout的方式
1.手写代码添加constraints(如下图)
向上面这样的写法不过是把一个视图的centerX ,centerY于父视图响应的centerX,centerY对齐(忽略这缎带代码中的constant参数,暂时把它们都当作0吧),却也要写一大段,看着也很费劲,不过官方的API这样设计当然是有道理的,我们要完全的控制布局,就得要这么多的参数,不过这样的方式显然我不会喜欢。
2.Xib文件拖拽添加约束
既然有手写代码添加constraints,当然会有Xib添加constraints的方式了。这种方式相对于手写代码带来的是,少了很多让人烦的代码,直接操作视图拖拽的便捷性,当然也有很多的缺点,比如这种方式很容易出现警告,错误,不容易更改等,都是因为相对于手写代码要注意的地方更多。比如我在项目中添加的constraints:(如下图)
看到这样的xib你是不是快疯了,如果把这样xib要重新布局设计,换一个人来做,那个人肯定是痛苦死了。
说到这里,好像是一直在吐槽autolayout的缺点一样。难道就没有简单的方式吗?当然有,在你意识到这些缺点的时候,相信有很多人都会试着去改善这些,比如masonry这个第三方库,就很好的为我们提供了一种简便的手写代码添加constraints的方式:(如下图)
是不是很方便也很容易理解,这就是了,我也在项目的很多地方用到了它,为我省去了很多的时间。
3.tableView,collectionView中的autoLayout
说到这里才是真正的到了正题,在app的开发中,列表视图时最常用的一个UI控件,当我们使用tableView或者是collectionView的时候,免不了的要对cell进行计算height,size,这时候正是autolayout大显身手的地方了。这里说一下tableView使用autolayout的一些细节,collectionView同理。
比如要实现这样的一个列表:
cell中有两个动态变化的因素,1 是文本的长度不固定,2 是图片的尺寸不固定,这样就导致了cell的高度是动态变化的,从服务器获取到数据以后展示,cell要根据数据动态的布局,如果有图片则根据图片尺寸展示图片和文本,如果没有图片则只展示文本,文本的最大行数为4行。这里我用的一种cell来做,或许你会说为什么不分两种类型的cell来做,我要说的是两种又怎么样,cell图片的尺寸又不是固定的,分两种还是要动态的计算高度啊!!!如果是same这样的那就简单一些了
虽然每个cell的高度也是动态的,但是cell中动态变化的挚友文本,而图片的尺寸却是固定的,不论你的图片的长宽比时怎么样的,看图 6的这种布局,图片上下都有一坨空白,是不是有点傻?好了,有了比较以后就继续吧。
一下时我的cell.m中的代码片段
首先我在awakeFromNib中对cell的contentView子视图做了一些配置,这里需要注意的是self.contentView.translatesAutoresizingMaskIntoConstraints=NO;把xcode为你自动添加的autoresizingMask标记为失效,这样cell就会真正完全的按照你自己的布局来工作,self.contentLabel.preferredMaxLayoutWidth=kScreenWidth-74;这个就是设置文本那个label的最大展示宽度,autolayout会根据这个值来布局。
然后使用数据填充cell的时候,看是否有图片,有图片就设置imageSize为响应的size,没有则设置图片为CGSizeZero,调用[self setNeedsUpdateConstraints];
[self updateConstraintsIfNeeded]; 告诉cell要更新constraints了,然后在cell的系统方法里面更新constraints:
这样cell的布局就完了。接下来看tableView的dataSource都写了些什么:
简单吧,没有计算高度的协议方法,只需要把数据丢给cell,当然前提是你的deployment target >= 8.0,并且需要设置self.tableView.estimatedRowHeight=100(大于0);就好了。
如果你要支持8.0以下的话加上下面这个方法吧。
就此不对这个方法里的布局方法做详细描述。