上一次写博客已经是4个月之前了,不是不想写,只是没找到太合适的题目,本人秉着宁缺毋滥的原则......
好吧,我承认是我懒惰了;
四个月,虽然陆续提交了几个项目,但是所学所用变化不大;与此同时,随着公司人事比较大的变动,我也重新找到了自己的位置,希望自己能百尺竿头,更进一步^_^
今天想写的,题目已经表示出来了,灵感的来源是“iOS进阶指南试读之UI篇”这篇文章,正好下午没事就实践了一下,下面就把实践的一些东西记录一下;
最早还是自己手动写cell的时候,还是通过计算frame的方式进行UI布局,记得是iOS8出来的时候吧,正好二期项目开始,就和当时的同事一起学习了如何使用autolayout进行UI布局,因为要进行6s和6plus的适配,一开始确实有些怪,但后来慢慢也就习惯了,觉得很好用,但是对于cell的高度还是要算(其实可以自适应,后边会讲到),限于对autolayout的理解程度,一篇UI上的约束我自己看着都乱;
我会分别对三个label(1、2、3)进行 距上-距左-距右,以及高度的约束设置(注意label3没有距下的约束);然后在Controller中根据拿到的数据源进行文本显示区域高度的计算以契合该cell,最后的cell高度由其内部各视图的高度计算得出,通过tableVIew的代理再设置一下;
是不是忍不了,我也忍不了,但是没办法啊>_<,不过没关系,当你读完这篇文章的时候,也许就不用在这样做了;
所谓autolayout,其实就是系统通过我们所设置的约束,对UI上的相关控件进行自动布局,那么约束就显得至关重要了;
上图所示的红色View,并在上面依次放了3个label,以label1为例,若按之前的方式,距上-距左-距右,以及高度的约束设置,就可以确定这个视图的位置固定;
如果是UIView的话,只有距上-距左-距右,那么Xcode就会提示需要进行高度的设置,因为如果不进行高度的设置,这个视图的位置是无法确定的:
autolayout的本质就是系统通过你设置的约束帮你计算一个控件的位置和大小;
但如果是UILabel的话,只有距上-距左-距右,那么Xcode则不会提示,即不需要进行高度约束的设置:
之所以有这种情况,是因为有些视图可以通过自己的额内容计算高度,而有些视图则不可以;对应所要讲的就是我们的小标题 Intrinsic Content Size(固有内容大小);
对应的系统方法是 -(CGSize)intrinsicContentSize;
一个UIlabel肯定具备四个条件:内容、字体、行数、换行模式;即只要赋予了label内容,label的大小也就确定了,也因此,我们不需要特意指定一个UILabel的宽高(特殊要求除外);
UIView不可以自己计算大小,则是因为他没有内容;
那如果我们不想用label自己计算的高度,或是UIView的高度我们也不想通过添加约束的方式来设置,利用Intrinsic Size的Placeholder,我们是可以做到的;
我们先看一个例子:基于上图,我们把label的高度拉大一点,Xcode会给出一个警告,意思是 真实的高度是44,但自己计算的却不是这个值,如下图;
我们看到默认使用系统定义的,对应的也就是现在警告的情况;
我们在xib中将Intrinsic Size属性设置为Placeholder,这样就不会报错了(如下图):
这个属性的作用就是给相应视图提供一个默认的大小;
如果是代码实现的可以在UILabel的子类中,重写 -(CGSize)intrinsicContentSize;方法,如:
- (CGSize)intrinsicContentSize
{
CGSize originalSize = [super intrinsicContentSize];
CGSize size = CGSizeMake(originalSize.width+20, originalSize.height+20);
return size;
}
表示:先获取系统通过label内容计算出来的大小,再分别增大返回新的Size即可;
这两个概念需要结合我们上面讲的Intrinsic Content Size
来理解,每一个控件都有一个系统计算的最佳大小:Content Hugging Priority
这个属性就代表着,一个控件拒绝本身size大于InstrinsicSize
的优先级;Content Compression Resistance
,这个属性代表着,一个控件拒绝本身size小于InstrinsicSize
的优先级;
优先级越高,拒绝的程度就越大,也就是最后才会被拉伸或压缩;
我们举一个例子:
1.新建一个cell,UI同这篇blog的第一张图;
2.label的约束均为:距上 距下 距左 距右(不设宽高,自动计算);
3.然后我们改变cell的宽高;
如果3个label的拉伸或压缩优先级的相同(上图中的251 750)是不被允许的,因为随着cell的宽高变化,label面临一个问题,在保持和父View间距不变的情况下,必须有一个label做出妥协,即进行宽高的变化,否则Xcode是不知道到底该拉伸哪个Label的;
那到底那个先做出妥协,这就是这两个属性的作用;
我们对label1-label2-label3做出以下优先级调整:
即随着cell的变化,3个label是有一个变化顺序的,看看下面的图示,是不是和我们预想的一样:
在做这个Demo时,我忽然想起,许久之前看到的关于iOS8上,cell高度自适应的属性设置,那时还不甚理解,现在看来其实原理就是基于有些控件的高度自动计算反推cell的高度,那时系统也还需要满足iOS7,也就搁置了,现在的项目是基于iOS8的,接下来就让我们来操作一下:
1.新建一个cell,UI同这篇blog的第一张图;
2.label的约束均为:距上 距下 距左 距右(不设宽高,自动计算);
3.红色View的约束为:距上 距下 距左 距右;
tableView设置rowHeight为UITableViewAutomaticDimension,表示自动计算cell尺寸:
self.tableView.estimatedRowHeight = 50.0f;
self.tableView.rowHeight = UITableViewAutomaticDimension;
我们再将数据源设置为不同长度的文本:
[self.tableArray addObjectsFromArray:@[@{@"label1":@"auwefhauwehf",
@"label2":@"auwefhauwehf",
@"label3":@"auwefhauwehf"},
@{@"label1":@"auwefhauwehfauwefhauwehf",
@"label2":@"auwefhauwehfauwefhauwehf",
@"label3":@"auwefhauwehfauwefhauwehf"},
@{@"label1":@"auwefhauwehfauwefhauwehfauwefhauwehf",
@"label2":@"auwefhauwehfauwefhauwehfauwefhauwehf",
@"label3":@"auwefhauwehfauwefhauwehfauwefhauwehf"}]];
运行代码,结果如下:
我们看到:
虽然我们设置的预计的RowHeight是50,但是实际显示出来的cell确实根据各个label自己计算出来的高度得出来的,而我们并没有设置任何一个label的高度约束;
当然,这多亏了iOS8提供的UITableViewAutomaticDimension;
总结:
在写这篇blog时,内心有些小激动,因为我知道,这将改变我原来对UI布局的诸多认知,也希望对大家有所帮助;
之前还在Xcode中新建了一些类的模板,很受用,再写的话就把这个写了,哈哈^_^;
感谢叶孤城___(简书作者)的“iOS进阶指南试读之UI篇”,使这篇文章成为可能。