(iOS)使用auto layout进行复杂布局时,UILabel的相关trick
本文首发于CSDN:http://blog.csdn.net/madongchunqiu/article/details/47960745。若作者没有回复,请email至:madongchunqiu@gmail.com
给心急的同学先说说结论:(因为我也是一个心急的同学)
1. 对于UILabel,设置number of lines相当于设置了一个纵向的constraint;也即意味着,UILabel设置三个constraint就够了
2. 对于UILabel,横向设置一个"<="的constraint,可以让UILabel自行适配宽度
3. 文章结尾有测试题哦,喜欢挑战的同学请往后看
一。正文:
先来一段情怀。
第一个项目是纯手码的,MRC,且几乎没有使用第三方库。整天乐呵呵的在纸上计算布局的坐标,各种大小都是根据比例实时计算的。缺点显而易见,布局的代码太多,把逻辑部分的代码都挤没了;好处是,我感觉超可控,几乎没有意料外的bug,也不会怕苹果更新版本影响到app的使用。(注:最新的版本使用storyboard进行界面切换,大多数布局还是手码的)
第二个项目过于庞大,我使用了Storyboard+auto layout,ARC,数个4位数Star且维护活跃的第三方库。设计师对UI的控制超精细,auto layout真正让我从界面布局中解放出来了。不过从最开始机械的使用“横向两个constraint+纵向两个constraint”,到现在主要使用“UITableView+FDTemplateLayoutCell”(https://github.com/forkingdog/UITableView-FDTemplateLayoutCell)进行tableviewcell的布局,还是有些值得讨论和学习的地方。
二。讨论对象:
以下均假设场景为使用UITableViewCell进行布局,UITableViewCell内有数个Label/Image/Button等复杂排版。一般而言,Image和Button的大小不变或者和Cell保持比例关系,比较容易处理;而Label则可能由于文字的长短,字体大小的变化,导致宽度和高度上的变化,带来计算上的麻烦。
另外,本文针对实战,对其中的原理部分并未涉及,我觉得下面这篇文章写的不错,若想深入了解可以一读:深入理解Auto Layout 第一弹(http://zhangbuhuai.com/2015/07/16/beginning-auto-layout-part-1/)
三。设置方法
1:基本款
采用“横向两个constraint+纵向两个constraint”的方法,精确到point的控制每个界面元素的位置和大小。如下图:
上图为Label设置了Top, Left, Righ和Height4个属性,即可完全控制Label的大小。
但,若Label中需要显示的内容可能占用多行,则可以将number of lines设置为0(有时标题最多显示两排时,则可设置为2),然后将Height这个constraint牵出来作为IB Outlet,则可以在程序中随时修改,如下图:
由于文字长短和cell的宽度均会影响Label的布局,从而决定cell的高度,因此heightForRowAtIndexPath:的返回值需要通过计算得到。因此此cell会实现两个函数:
- + (CGFloat)cellHeightWithData:(MDDataType*)data withCellWidth:(CGFloat)cellWidth;
- - (void)updateWithData:(MDDataType*)data withCellWidth:(CGFloat)cellWidth;
前者class method由heightForRowAtIndexPath:调用,避免实例化cell。其中调用
- [data.text boundingRectWithSize:CGSizeMake(cellWidth-margin, MAXFLOAT)
- options:NSStringDrawingUsesLineFragmentOrigin
- attributes:@{NSFontAttributeName:label.font}
- context:nil].size.height
来计算label的高度,然后合成整个cell的高度
后者instance method由cellForRowAtIndexPath:调用,实例化cell中的各个控件参数,然后将上面代码的计算结果赋值给constraint的IB Outlet.
优点:计算快捷效率高,控制精准。
缺点:IB中设置的gap,margin等数值需要和cellHeightWithData此函数中使用的hardcode数值保持一致,一个数据两方维护,简直不能忍。另:若Label的字体大小变化,则可能需要重新设置,不方便。
2. 自适应款
利用constraint中的"ratio","multiply",">=","<="等设置,完成auto layout的自动布局。
这个设置是在前面的设置中,删掉了Height这个constraint,这个时候,可以理解为number of lines充当了第四个constraint,从而可以让auto layout进行布局。果不其然,auto layout提示说该布局和运行后不符(运行后被auto layout到正确的位置了)。这个warning一方面告诉我们说auto layout可以正确handle这个label,另一方面告诉我们应该用"Update Frame"这个方法将Label摆放正确。
另一种情况,某些label可能无法占满整个横向区域,其后可能会有别的控件,可以设置"<="constraint,使其进行自动布局,如图:
自适应布局,加上前面提到的“UITableView+FDTemplateLayoutCell”(https://github.com/forkingdog/UITableView-FDTemplateLayoutCell),所有关于布局之类的margin,gap等等,就只用在IB中搞定了。几乎没必要牵出constraint作为outlet来手动设置了。并且cell所需要实现的函数仅为:
- - (void)updateWithData:(MDDataType*)data;
在heightForRowAtIndexPath:和cellForRowAtIndexPath:中均调用此函数即可。【具体请参考UITableView+FDTemplateLayoutCell的文档和源代码】
优点:布局全部在IB中,代码中几乎可以不用管
缺点:由于heightForRowAtIndexPath中需要实例化cell,且进行布局计算,因此效率会稍低(当然,会有些优化方法)
四。使用场景
A. 均一高度
hardcode吧,多好啊
(截图自:网易新闻)
B. 易算高度
比如高度和宽度比例为16:9,使用class method进行计算吧,多好啊。
- + (CGFloat)cellHeightWithData:(MDDataType*)data withCellWidth:(CGFloat)cellWidth;
(截图自:美团)
C. 复杂布局+不需要考虑效率
使用UITableView+FDTemplateLayoutCell吧
(无图)
D. 复杂布局+效率优先
需要特殊情况特殊对待
(无图)
五。习题
i) 习题一:某个列表由tableview实现,每个cell都有很多信息,其中Title可长可短,短的显示一行,长的最多显示两行。标题旁显示Date,有如下四种情况:
情况1:标题占一行,且可以在右侧放置日期,则标题和日期放置在同一行
|---------------------------------------------|
| Title Short Date |
| (Others) |
情况2:标题占一行,但第一行容纳不下日期,日期放在第二行
|---------------------------------------------|
| Title Ratherrrrrrrrrrrrrrrrrrrrrrrrr Long |
| Date |
| (Others) |情况3:标题占两行,第二行可以在右侧防止日期,则日期放置在第二行
|---------------------------------------------|
| Title Verrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr |
| rrrrrrrrrrrrrrrry Long Date |
| (Others) |
情况4:标题占两行,但第二行容纳不下日期,则日期放在第二行,标题Trunk Tail,显示"..."
|---------------------------------------------|
| Title Terrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr |
| rrrrrrrrrrrrrrrrrrrrrrrrrrrriblely ... Date |
| (Others) |
|-------------------------------------|
| II |
| III |
| IIIIIIIIIIIIIIIIIIIIIIIIIIIIII |
| III III |
| III III |
| III III |
| III IIII |
| II IIIII |
| I IIIIII |
| (Others) |
或者
| II II |
| II II |
| III II III III II III |
| III II III III II III |
| VII VII |
| (Others) |
iii) 更多习题...
版权声明:本文为博主原创文章,未经博主允许不得转载。