美文网首页iOS
iOS11中tableView的一个陷阱

iOS11中tableView的一个陷阱

作者: 西山薄凉 | 来源:发表于2017-09-29 17:19 被阅读74次

    首先说明是什么坑:iOS11中tableView默认开启self-sizing,这会导致heightForRow代理方法与cellForRow数据源方法调用顺序的改变。

    Self-Sizing在iOS11下是默认开启的,Headers, footers, and cells都默认开启Self-Sizing,所有estimated 高度默认值从iOS11之前的 0 改变为UITableViewAutomaticDimension
    如果目前项目中没有使用estimateRowHeight属性,在iOS11的环境下就要注意了,因为开启Self-Sizing之后,tableView是使用estimateRowHeight属性的,这样就会造成contentSize和contentOffset值的变化,如果是有动画是观察这两个属性的变化进行的,就会造成动画的异常,因为在估算行高机制下,contentSize的值是一点点地变化更新的,所有cell显示完后才是最终的contentSize值。因为不会缓存正确的行高,tableView reloadData的时候,会重新计算contentSize,就有可能会引起contentOffset的变化。

    这是你可能需要为你的 APP 适配 iOS 11这篇文章中的一段。

    按照这篇文章,将App中大大小小的地方处理过之后,发现聊天界面出现了奇怪的问题,如图:

    聊天界面

    部分cell出现了气泡大小不正确的问题。

    经过反复排查,发现代码中气泡大小的计算是写在heightForRow方法中,按照之前的调用顺序,先调用heightForRow计算好气泡大小,后调用cellForRow数据源时就可以直接取到气泡大小,这样是没有问题的。但iOS11中默认开启了self-sizing,这样会导致这两个方法调用顺序的改变,先调用cellForRow自然就没法取到正确的行高了。

    解决方法很简单,如下

    self.tableView.estimatedRowHeight = 0;
    self.tableView.estimatedSectionHeaderHeight = 0;
    self.tableView.estimatedSectionFooterHeight = 0;
    

    第一句将估算行高设为0,既关闭行高自适应自动计算行高,这样代理方法的顺序就又和之前的一样了。为了稳妥起见,又加上了后面两句关闭组头组尾的行高估算。

    至于为什么开启估算行高会引起这个问题,本人的猜测是,tableView的默认行高是44.f,如果给rowHeight属性赋值或者重写了heightForRow方法,系统就会先取自定义的高度,但是一种例外就是开启了自适应行高。

    恩,听上去蛮靠谱的。我们知道,UITableView 是个 UIScrollView,就像平时使用 UIScrollView 一样,加载时指定 contentSize 后它才能根据自己的 bounds、contentInset、contentOffset 等属性共同决定是否可以滑动以及滚动条的长度。而 UITableView 在一开始并不知道自己会被填充多少内容,于是询问 data source 个数和创建 cell,同时询问 delegate 这些 cell 应该显示的高度,这就造成它在加载的时候浪费了多余的计算在屏幕外边的 cell 上。

    上面一段是阳神的一篇文章中的,当开启了自适应行高,系统就会去先获取到对应的cell通过计算约束或者sizeThatFits来获取cell的真实高度,然后再调用heightForRow来看是否有用户指定的行高。这样就会导致这两个方法调用顺序的变化。

    相关文章

      网友评论

      • Sui_H:楼主你好,我用kvo监听wkwebview的contentSize的值,三个属性全部为0,发现tableview会一直reloadData的,有什么要解决办法没。
        西山薄凉:KVO监听是没问题的,你需要确定为什么tableView会一直reload。

      本文标题:iOS11中tableView的一个陷阱

      本文链接:https://www.haomeiwen.com/subject/xqoiextx.html