在使用 table view 的时侯经常会遇到这样的需求:table view 的 cell 中的内容是动态的,导致在开发的时候不知道一个 cell 的高度具体是多少,所以需要提供一个计算 cell 高度的算法,在每次加载到这个 cell 的时候计算出 cell 真正的高度。

在 iOS 8 之前

没有使用 Autolayout 的情况下,需要实现 table view delegate 的 tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat 方法,在这个方法中计算并返回 cell 的高度。比如,我有一个可以显示任意行数的纯文本 cell,计算 cell 的代码可以是这样:

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    let content = self.datas[indexPath.row] as String
    let padding: CGFloat = 20
    let width = tableView.frame.size.width - padding * 2;
    let size = CGSizeMake(width, CGFloat.max)
    let attributes = [NSFontAttributeName: UIFont(name: "Helvetica", size: 14)!]
    let frame = content.boundingRectWithSize(size,
        options: NSStringDrawingOptions.UsesLineFragmentOrigin,
        attributes: attributes,
        context: nil)
    return frame.size.height+1;
}

上面的代码是一个最简单的例子,这个例子看起来好像没有什么问题。但是通过查看这个 delegate 方法的文档后,可以知道,在每次 reload tableview 的时候,程序会先计算出每一个 cell 的高度,等所有高度计算完毕,确定了 tableview 的总的高度后,才开始渲染视图并显示在屏幕上。这意味着在显示 table view 之前需要执行一堆的计算,并且这是在主线程中进行的,如果计算量太大程序就很有可能出现卡顿感。比如: table view 的数据有上千条,或者计算高度的代码中还要先获取图片再根据图片计算高度,这些操作都是非常慢的。

如果在 cell 中使用了 autolayout,在计算 cell 高度时会更麻烦。有兴趣的可以看这里有篇关于如何在 autolayout 下动态计算高度的文章。

为 什么不能等滚动到某个 cell 的时候,再调用计算这个 cell 高度的 delegate 呢?原因是 tableview 需要获得它的内容的总高度,用这个高度去确定滚动条的大小等。直到 iOS 7 UITableViewDelegate中添加了新的 API:

tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat

这 个方法用于返回一个 cell 的预估高度,如果在程序中实现了这个方法,tableview 首次加载的时候就不会调用heightForRowAtIndexPath 方法,而是用 estimatedHeightForRowAtIndexPath 返回的预估高度计算 tableview 的总高度,然后 tableview 就可以显示出来了,等到 cell 可见的时候,再去调用heightForRowAtIndexPath 获取 cell 的正确高度。

通 过使用estimatedHeightForRowAtIndexPath 这个 Delegate 方法,解决了首次加载 table view 出现的性能问题。但还有一个麻烦的问题,就是在 cell 没有被加载的时候计算 cell 的高度,上面给出的代码中,仅仅是计算一个 NSString 的高度,就需要不少代码了。这种计算实际上是必须的,然而在 iOS 8 开始,你可能可以不用再写这些烦人的计算代码了!

iOS 8 的魔法

在 iOS 8 中,self size cell 提供了这样一种机制:cell 如果有一个确定的宽度/高度,autolayout 会自动根据 cell 中的内容计算出对应的高度/宽度。

TableView 中的 cell 自适应

要让 table view 的 cell 自适应内容,有几个要点:

1.设置的 AutoLayout 约束必须让 cell 的 contentView 知道如何自动延展。关键点是 contentView 的 4 个边都要设置连接到内容的约束,并且内容是会动态改变尺寸的。

2.UITableView 的 rowHeight 的值要设置为 UITableViewAutomaticDimension

3.和 iOS 7 一样,可以实现 estimatedHeightForRowAtIndexPath 方法提升 table view 的第一次加载速度。

4.任何时候 cell 的 intrinsicContentSize 改变了(比如 table view 的宽度变了),都必须重新加载 table view 以更新 cell。

例子

在 Xcode 中新建一个项目,在 storyboard 中创建一个 UITableViewController 的 IB,创建一个如下样子的 cell:

这个 cell 中有 3 个元素,其中 imageView 的 autoLayout 约束为:

imageView 左边离 contentView 左边 0

imageView 上边离 contentView 上边 0

imageView 的 width 和 height 为 80

imageView 下边离 contentView 下边大于等于 0(为了防止内容太少,导致 cell 高度小于图片高度)

titleLabel 的 autoLayout 约束为:

titleLabel 左边离 imageView 右边 8

titleLabel 上边和 imageView 上边在同一只线上

titleLabel 右边离 contentView 右边 0

titleLabel 下边离 description 上边 8

titleLabel 的高度小于等于 22,优先级为 250

descriptionLabel 的约束为:

descriptionLabel 左边和 titleLabel 左边在同一直线上

descriptionLabel 上边里 titleLabel 8

descriptionLabel 下边里 contentView 下边 0

descriptionLabel 右边离 contentView 右边 0

然后在这个 IB 对应的 UITableViewController 中加载一些数据进去,显示效果如图:

实 现这个效果,我除了设置了 autoLayout,还设置了 tableView 的 rowHeight = UITableViewAutomaticDimension,然后就是这样了。一点计算 cell 高度的代码都没有!!我连 heightForRowAtIndexPath都不用实现,真的是….爽出味啊!所以如果已经在开发 iOS 8 Only 的应用了一定要用autolayout,把烦人的计算交给 autolayout 去吧。

CollectionView 中的 cell 自适应

在 collection view 中也能让 cell 自适应内容大小,如果 UICollectionView 的 layout 是一个 UICollectionViewFlowLayout,只需要将 layout.itemSize = ... 改成 layout.estimatedItemSize = ...。 只要设置了 layout 的 estimatedItemSize,collection view 就会根据 cell 里面的 autolayout 约束去确定cell 的大小。

原理:

1.collection view 根据 layout 的 estimatedItemSize 算出估计的 contentSize,有了 contentSize collection view 就开始显示

2.collection view 在显示的过程中,即将被显示的 cell 根据 autolayout 的约束算出自适应内容的 size

3.layout 从 collection view 里获取更新过的 size attribute

4.layout 返回最终的 size attribute 给 collection view

5.collection 使用这个最终的 size attribute 展示 cell

总结

这 次 iOS 8 的发布对 UI 开发来说是越来方便了,很多以前需要写大量计算的代码现在都可以通过拖拖 IB 上的 UI 控件就可以实现了,当然首先你要会 autolayout。 如果很幸运的在开发 iOS 8 only 的应用,真的可以删除heightForRowAtIndexPath中那些繁重的计算代码了!让 autolayout 帮我们完成所有的工作吧。

iOS 8 自适应 Cell的更多相关文章

  1. iOS tableViewCell自适应高度 第三发类库

    在github中有许多大牛封装好的第三发类库,其中有个自适应cell高度的类库 下载地址:https://github.com/gsdios/SDAutoLayout model类 commentsM ...

  2. IOS Table中Cell的重用reuse机制分析

    IOS Table中Cell的重用reuse机制分析 技术交流新QQ群:414971585 创建UITableViewController子类的实例后,IDE生成的代码中有如下段落: - (UITab ...

  3. iOS 点击cell下拉

    iOS  点击cell下拉 代码如下: #import "ViewController.h" @interface ViewController ()<UITableView ...

  4. iOS 键盘自适应(IQKeyboardManager)使用小结

    IQKeyboardManager Github地址 经常在开发一个应用程序,我们遇到了一个问题,iPhone的键盘上滑覆盖的UITextField / UITextView.IQKeyboardMa ...

  5. ISO 8 自适应cell

    原文网址: http://www.cocoachina.com/ios/20141218/10687.html 在使用 table view 的时侯经常会遇到这样的需求:table view 的 ce ...

  6. iOS UITableViewableViewCell自适应高度

    前两天做了一个项目,中间有遇到一个问题,就是聊天的时候cell高度的问题.这是一个很多前辈都遇到过,并且很完美的解决过的问题.这里主要是记录自己的学习心得.项目中首先想到的是用三方库,可是有问题,遂放 ...

  7. iOS - UITableView中Cell重用机制导致Cell内容出错的解决办法

    "UITableView" iOS开发中重量级的控件之一;在日常开发中我们大多数会选择自定Cell来满足自己开发中的需求, 但是有些时候Cell也是可以不自定义的(比如某一个简单的 ...

  8. ios中自定义cell 设置cell的分组结构

    ios系统默认的cell并不能满足我们的需求 这个时候就需要自定义我们的cell 自定义cell为分组的时候 需要设置分组样式  以下是我常用分组的二种方法: 第一是 在自定义的UITableView ...

  9. iOS开发之cell多按钮

    iOS开发经常出现cell需要多个按钮,一般以为要导入第三方框架.但其实iOS 8以后,系统提供了UITableViewRowAction以及新的delegate方法,使得自定义一些操作变得非常容易. ...

随机推荐

  1. js获取每个按键的ASCII值

    通过js绑定键盘按下事件onkeydown获取每个按键的ascII值. js获取每个按键的ascii值 <script language="javascript"> / ...

  2. Android--Service之绑定服务交互

    前言 开篇名义,这篇博客介绍一下Android下使用绑定服务进行时数据交互的几种方法.关于Android下Service的内容,前面两篇博客已经介绍了,不清楚的可以移步过去先看看:Android--S ...

  3. http://msh.baidu.com/UTWpR6wY4722

    超人的计算机专业应届研究生个人简历,但企业不需要 前几天和一位做人力资源的朋友在饭店里面喝酒,聊起来大学生找工作不好找的话题.我的这个朋友对这个还真比较感兴趣,说着说着从公文包里拿出来一份简历递给我看 ...

  4. 206.反转单列表 Reverse Linked List

    Reverse a singly linked list. 使用栈 public class Solution { public ListNode ReverseList(ListNode head) ...

  5. android上line-height的问题

    关于line-height大家应该非常熟悉了吧,就是用来做垂直居中的,屡试不爽,基本上没有什么问题,但是最近一个项目,测试提了一个bug,看图吧. 从别处窃的图,这个问题只有安卓上才能复现,做了dem ...

  6. iOS 点击cell下拉

    iOS  点击cell下拉 代码如下: #import "ViewController.h" @interface ViewController ()<UITableView ...

  7. 强大的微软Microsoft Translator翻译接口

    一.前言 当我们需要对日文.韩文等语言转换中文字符的时候,就用到了微软提供的翻译接口. 二.实现流程 1.首先注册一个账号 https://datamarket.azure.com/account 2 ...

  8. SwfUpload及imgareaselect使用方法

    1.导入文件 Swfupload相关文件 imgareaselect截取插件相关文件 2.前端html代码 添加一个截取图片的按钮,其他为swf所需的html. <body> <di ...

  9. python中os.walk()遍历目录中所有文件

    之前一直用判断目录和文件的递归方法来获取一个目录下的所有文件,后来发现python里面已经写好了这个函数,不需要自己递归获取了,记录下os.walk()函数的用法 目的:获取path下所有文件,返回由 ...

  10. linux pc syncy安装问题

    linux pc 上安装syncy遇到的坑 pycurl安装可以指定curl-config,这个是根据自己机器libcurl安装位置确定,不在默认位置时要指定:python setup.py inst ...