zoukankan      html  css  js  c++  java
  • (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) 更多习题...

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

  • 相关阅读:
    (C/C++)区别:数组与指针,指针与引用
    C++中数组名和指针的区别联系
    C++引用的用处
    C++编写DLL动态链接库的步骤与实现方法
    C++_编写动态链接库
    C++ 模板
    C++ 信号处理
    C++ 多线程
    js事件冒泡
    js事件委托
  • 原文地址:https://www.cnblogs.com/Camier-myNiuer/p/4873623.html
Copyright © 2011-2022 走看看