更新提示:
【2018年11月20日更新】
经过放置在项目中运行发现,如果在快速滚动tableview的时候会在下面这行代码中崩溃(慢慢的滚动是没关系的~):
CGFloat cellHeight = [tableView rectForRowAtIndexPath:[NSIndexPath indexPathForRow:(indexPath.row - 1) inSection:indexPath.section]].size.height;
提示的error原因是,超出数组的范围进行访问。原因,后面有时间会详细说明更新进来,大致的原因就是利用rectForRowIndexPath方法去取cell的时候,从展示在界面上的第一个完整的cell开始作为下标为0的cell。比如,一个界面中可以存放4个cell,第5个cell将要展示的时候,会在界面中去取下标为3的cell。有一点需要插播一条,就是在第5个cell还没有漏出来之前,系统就会去调用tableview的cellForRowAtIndexPath协议方法了,这就是为什么你慢慢的滚动tableview是没有关系的。如果快速滚动的话,虽然系统也是在第5个cell还没有漏出来之前就去调用那个协议方法了,但是等到运行到rectForRowIndexPath方法的时候,第1个cell就已经被顶出tableview的可视区域了,这个时候下标为0的cell就是从开始的第2个cell开始了(第一个cell在屏幕中的部分并不是完整的了),所以就会抛出异常。
暂时先把“indexPath.row - 1”的“-1”改为“-2”暂且应付。
因为如果tableview的可视范围最多只能同时容纳2个完整的cell的话,使用“-2”就会往前超域访问数组;如果最多只能同时容纳1个完整的cell的话,使用“-1”也会往前超域访问数组;如果连一个完整的cell都容纳不下,那么这个方法就根本行不通了。(很尴尬~)
问题背景:
使用MJRefresh一直都很方便,适配到iOS11以后,tableView上拉加载更多数据动画结束后,出现tableView跳动、闪动的现象。
通过浏览Github上的MJRefresh的Issues后发现,很多人都遇到了这个问题。而且,一般遇到这个问题的都是使用自动化布局来自动约束Cell高度的同学。如果将Cell是通过tableView的rowHeight属性或者对应的协议方法给定的,就不出遇上这个问题。
分析问题:
为了实现Cell的高度自适应,需要做三步:
1、不要设置rowHeight、不要重写设置rowHeight的协议方法
2、在搭建Cell的UI时,让最后一个控件的bottom等于cell.contentView.mas_bottom(这里用masonry举例)
3、设置tableView的下面两个属性:
self.estimatedRowHeight = 44; self.rowHeight = UITableViewAutomaticDimension;
有同学说,走回以前“根据内容计算好cell的高度”的方式,很定是不合适的,与苹果推崇的AutoLayout相违背。
所以使用上面的高度自适应方式,是没错的,错就错在
estimatedRowHeight
这个属性的设置。
如果通过高度自适应计算出来Cell的真实高度与给出的估算高度相差太大,很定出现view渲染过程的异常。
解决方式:
根据上面的分析,本ID采用的方式是加载cell时,将上一个cell对象的高度设置为下一个即将出现的cell的预估高度。
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row > 1) { CGFloat cellHeight = [tableView rectForRowAtIndexPath:[NSIndexPath indexPathForRow:(indexPath.row - 1) inSection:indexPath.section]].size.height; self.estimatedRowHeight = cellHeight; } //。。。你之前的代码 return cell; }