垂直UICollectionView分页跳转异常,如何修改分页尺寸?
解决UICollectionView垂直布局下自定义分页尺寸的问题
我太懂这个痛点了!之前做垂直卡片流的时候,默认的isPagingEnabled完全不管Cell大小,直接按整个CollectionView的高度分页,试了自定义布局和第三方库要么卡顿要么跳Cell,后来发现用原生的UIScrollView代理就能完美解决,流畅度和原生分页一样丝滑!
核心思路是关闭默认分页,手动控制滚动结束时的偏移量,让它停在每个Cell的起始位置。具体步骤如下:
1. 关闭默认分页并设置代理
首先,把CollectionView的默认分页关掉,同时把它的delegate设为当前ViewController:
collectionView.isPagingEnabled = false collectionView.delegate = self
2. 实现UIScrollView代理方法控制分页
关键是实现scrollViewWillEndDragging(_:withVelocity:targetContentOffset:)这个方法,它能拦截滚动结束时的目标偏移量,我们可以把它修正到对应Cell的位置:
extension YourViewController: UIScrollViewDelegate { func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) { // 先拿到布局(假设用的是UICollectionViewFlowLayout) guard let flowLayout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout else { return } // 计算单个Cell的高度 + 行间距(也就是每次分页的步长) let cellHeight = collectionView.bounds.height * 0.9 let lineSpacing = flowLayout.minimumLineSpacing let pageStep = cellHeight + lineSpacing // 获取系统计算的目标偏移量 var targetY = targetContentOffset.pointee.y // 根据滚动速度调整目标位置,避免惯性跳过Cell if velocity.y > 0 { // 向下滚动,取上整,确保滚到下一个Cell targetY = ceil(targetY / pageStep) * pageStep } else if velocity.y < 0 { // 向上滚动,取下整,确保滚到上一个Cell targetY = floor(targetY / pageStep) * pageStep } else { // 无速度时,取最近的Cell位置 targetY = round(targetY / pageStep) * pageStep } // 限制偏移量在合法范围内,防止滚出内容区域 let maxValidY = max(0, collectionView.contentSize.height - collectionView.bounds.height) targetY = min(targetY, maxValidY) // 把修正后的偏移量赋值回去 targetContentOffset.pointee.y = targetY } }
注意事项
- 如果你的布局不是
UICollectionViewFlowLayout,只需要自己计算每个Cell的起始Y值,然后找到最接近目标偏移量的那个Cell的Y值即可,原理是一样的。 - 如果CollectionView设置了
contentInset,计算的时候要把顶部/底部的inset考虑进去,比如targetY要先减去contentInset.top再计算,最后再加回来。 - 这个方法是原生UIScrollView的机制,完全不会有自定义布局的卡顿问题,也不会出现跳过Cell的情况,亲测好用!
内容的提问来源于stack exchange,提问作者Narek Simonyan
相关产品推荐
相关产品推荐

