最近遇到一个问题,当UITableView或UICollectionView使用动态行高,会出现初始行高不准,如果想滑动到指定位置,会出现偏差
如果是想要滑动到指定组,使用scrollToRow即可实现
本文主要讨论滑动到指定位置,或者滑动到指定组但是需要附加一定偏移量的场景
动态行高布局
设置初始默认行高
fileprivate let tableView: UITableView = UITableView(frame: CGRect.zero, style: .grouped).then {
$0.estimatedRowHeight = 100
$0.estimatedSectionHeaderHeight = 10
$0.estimatedSectionFooterHeight = 10
}
返回动态行高
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
cell内部使用Masonry或者SnpKit来进行布局
分析
因为行高是动态的,当下方的cell未滑动出现时,实际并未确定真实高度,此时设置滑动位置会出现偏差
尝试过设置contenOffset、 scrollToRow、 scrollRectToVisible等方法,均不能准确滑动到指定位置,因为滑动过程中才真正确定cell行高
实践中发现当整个UITableView或UICollectionView从头部滑动到尾部,此时设置滑动位置不会出现问题,因为cell已经加载出现,cell行高也已经确定
即:当使用动态行高布局,cell未加载出现时,行高未知,滑动会因此出现偏差
解决方案
通过两步结合来解决此问题
- 通过scrollToRow滑动到大概位置
- 在滑动过程中附加动画进行二次滑动偏移 scrollRectToVisible
func scrollToSection(tableView: UITableView, section: Int) {
tableView.scrollToRow(at: IndexPath(item: 0, section: section), at: .top, animated: true)
DispatchQueue.main.asyncAfter(deadline: .now()+0.2) {
var rect: CGRect = tableView.rect(forSection: section)
var rectOrigin = rect.origin
rectOrigin.y -= TWSwiftStatusAndNavigationHeigth + RentHouseDetailViewController.Metric.segMentViewHeight
rect.origin = rectOrigin
let insets = tableView.contentInset
rect.size = tableView.frame.size
rect.size.height -= insets.top + insets.bottom
let offsetY = (rect.origin.y + rect.size.height) - tableView.contentSize.height
if offsetY > 0.0 {
rect = rect.offsetBy(dx: 0, dy: -offsetY)
}
tableView.scrollRectToVisible(rect, animated: false)
}
}
动画效果较为连贯,不会出现肉眼可见二次偏移
这样的写法主要是可以解决cell未加载出现时,行高未知的问题;
在滑动到大概位置的时候,cell已经出现,行高确定,此时再进行偏移,可以准确滑动,不会出现偏差