(iOS)使用autolayout进行复杂布局时 UILabel的相关trick

本文首发于CSDN:http://blog.csdn.net/madongchunqiu/article/details/47960745

给心急的同学先说说结论:(因为我也是一个心急的同学)

  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则可能由于文字的长短,字体大小的变化,导致宽度和高度上的变化,带来计算上的麻烦。

三、设置方法

(以下两个方法各有运用场景)

1:基本款

采用“横向两个constraint+纵向两个constraint”的方法,精确到point的控制每个界面元素的位置和大小。如下图:

这里写图片描述

上图为Label设置了Top, Left, Righ和Height4个属性,即可完全控制Label的大小。

但,若Label中需要显示的内容可能占用多行,则可以将number of lines设置为0(有时标题最多显示两排时,则可设置为2),然后将Height这个constraint牵出来作为IB Outlet,则可以在程序中随时修改,如下图:

这里写图片描述

由于文字长短和cell的宽度均会影响Label的布局,从而决定cell的高度,因此heightForCellAtIndexPath:的返回值需要通过计算得到。因此此cell会实现两个函数:

+ (CGFloat)cellHeightWithData:(MDDataType*)data withCellWidth:(CGFloat)cellWidth;
- (void)updateWithData:(MDDataType*)data;

前者class method由heightForCellAtIndexPath:调用,避免实例化cell。其中调用

[label.text boundingRectWithSize:CGSizeMake(cellWidth, 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,且进行布局计算,因此效率会稍低(当然,会有些优化方法)

四、使用场景

(以下标题均描述uitableview中各个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 Ratherrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr Long |

| Date |

| (Others) |

情况3:标题占两行,第二行可以在右侧防止日期,则日期放置在第二行

|——————————————————|

| Title Verrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr |

| rrrrrrrrrrrrrrrry Long Date |

| (Others) |

情况4:标题占两行,但第二行容纳不下日期,则日期放在第二行,标题Trunk Tail,显示”…”

|——————————————————|

| Title Terrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr |

| rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrriblely … Date |

| (Others) |
ii) 更多习题。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值