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

本文转载至 http://blog.csdn.net/madongchunqiu/article/details/47960745 

本文首发于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会实现两个函数:

 

[objc] view plaincopy
 
  1. + (CGFloat)cellHeightWithData:(MDDataType*)data withCellWidth:(CGFloat)cellWidth;  
  2. - (void)updateWithData:(MDDataType*)data withCellWidth:(CGFloat)cellWidth;  

 

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

 

[objc] view plaincopy
 
  1. [data.text boundingRectWithSize:CGSizeMake(cellWidth-margin, MAXFLOAT)   
  2.     options:NSStringDrawingUsesLineFragmentOrigin   
  3.     attributes:@{NSFontAttributeName:label.font}   
  4.     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所需要实现的函数仅为:

 

[objc] view plaincopy
 
  1. - (void)updateWithData:(MDDataType*)data;  

在heightForRowAtIndexPath:和cellForRowAtIndexPath:中均调用此函数即可。【具体请参考UITableView+FDTemplateLayoutCell的文档和源代码】

 

优点:布局全部在IB中,代码中几乎可以不用管

缺点:由于heightForRowAtIndexPath中需要实例化cell,且进行布局计算,因此效率会稍低(当然,会有些优化方法)

 

四。使用场景

(以下标题均描述uitableview中各个cell的布局难度)
 

A. 均一高度

hardcode吧,多好啊

(截图自:网易新闻)

 

B. 易算高度

比如高度和宽度比例为16:9,使用class method进行计算吧,多好啊。

 

[objc] view plaincopy
 
  1. + (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) 习题二:某个列表中的tableviewcell中含有“全占式”大标题,即无论标题是啥,都要横向占满整个屏幕宽度,如下
 

|-------------------------------------|

|                 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) 更多习题...

版权声明:本文为博主原创文章,未经博主允许不得转载。

posted @ 2015-10-13 09:51  天牛  阅读(329)  评论(0编辑  收藏  举报