iOS Self-Sizing的一点优化 / 2019-08-05

在 iOS 11之后,UITableView默认开启了Self-Sizing。利用Self-Sizing技术,我们可以不需要实现heightForRowAt方法。但Self-Sizing可能会引起UITableView的闪烁问题,需要做一些优化处理。

我们知道:在 iOS 11之后,UITableView默认开启了Self-Sizing。利用Self-Sizing技术,我们不需要实现heightForRowAt方法,系统通过AutoLayout约束自动计算cell高度并绘制显示,这是一项非常不错的改进。但Self-Sizing可能会引起UITableView的闪烁问题,需要做一些优化处理。

开启Self-Sizing

iOS 10及之前版本需要配置:

tableView.estimatedRowHeight = 100.0
tableView.rowHeight = UITableView.automaticDimension

iOS 11之后仅需要配置:

tableView.rowHeight = UITableView.automaticDimension

在自定义的UITableViewCell中使用AutoLayout,不要实现heightForRowAt方法,即可使用UITableView的Self-Sizing。

同时,tableFooterView和tableHeaderView也是支持Self-Sizing的,不过需要通过systemLayoutSizeFitting的方法先获取其高度。

开启Self-Sizing 页面闪烁问题

当使用Self-Sizing滑动UITableView多次之后,执行reloadRows或reload很可能出现页面闪烁问题。

原因是即使使用了Self-Sizing技术,iOS系统还是要进行预估cell高度的操作,它会影响到滚动条的高度,如果提供的预估高度和实际cell的高度差别较大,就会带来闪烁问题。

一个比较好的改进方法是:

定义存储预估高度的map:

private var heightMap = [Int: CGFloat]()

增加实现estimatedHeightForRowAt和willDisplay的逻辑,分别获取和设置heightMap,即可解决UITableView闪烁问题。

func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
    if let value = heightMap[indexPath.row] {
        return value
    } else {
        return 100.0
    }
}

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    let key = indexPath.row
    if let _ = heightMap[key] {
    } else {
        heightMap[key] = cell.frame.size.height
    }
 }

其它文章

iOS安全:修改Mach-O
iOS:URL Decode中对于+号的处理
iOS APP灰度发布方案
iOS Method Swizzling使用陷阱
iOS URLSession Authentication Challenge及SSL Pinning