You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift 5中TableView开启isPagingEnabled无法滚动到完整高度下一个cell如何解决

问题原因

UITableView 继承自 UIScrollView,系统自带的 isPagingEnabled = true 逻辑是按ScrollView自身的frame高度进行分页,而非按cell高度分页。你的cell固定高度为755,只要该高度和TableView的实际frame高度不一致,就会出现滚动后cell显示不全的问题。

解决方案

要实现类似TikTok的逐cell完整滚动效果,推荐两种适配方案:

方案1:手动控制滚动停止位置(适配固定cell高度场景)

关闭系统自带分页,通过UIScrollView代理方法手动控制滚动到完整cell位置,步骤如下:

  1. 定义全局统一的cell高度、cell总数常量,保持所有相关场景取值一致
  2. 关闭系统分页,设置滚动减速速率优化手感
  3. 实现scrollViewWillEndDragging代理方法,手动计算目标cell位置并滚动

修改后的完整代码如下:

import UIKit

private let id =  "ss"
private let cellHeight: CGFloat = 755 // 统一cell高度
private let totalCellCount = 16 // 统一cell总数

class TableView:UITableViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: id)
        // 关闭系统自带分页
        tableView.isPagingEnabled = false
        // 设置更快的减速速率,接近TikTok滚动手感
        tableView.decelerationRate = .fast
    }
    
    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }
    
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return totalCellCount
    }
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: id, for: indexPath)
        cell.backgroundColor = .red
        return cell
    }
    
    override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return cellHeight
    }
    
    // 核心滚动控制逻辑
    override func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
        // 取消系统默认的滚动目标位置
        targetContentOffset.pointee = scrollView.contentOffset
        
        // 计算当前滚动位置对应的目标cell索引
        var targetIndex = round(scrollView.contentOffset.y / cellHeight)
        // 适配快速滑动场景,根据滑动速度调整目标索引
        if velocity.y > 0 {
            targetIndex += 1
        } else if velocity.y < 0 {
            targetIndex -= 1
        }
        // 处理边界,避免索引越界
        let finalIndex = max(0, min(Int(targetIndex), totalCellCount - 1))
        
        // 滚动到目标cell顶部
        tableView.scrollToRow(at: IndexPath(row: finalIndex, section: 0), at: .top, animated: true)
    }
}

方案2:cell高度适配TableView高度(适配全屏cell场景,实现更简单)

如果你的需求就是每个cell占满全屏,直接将cell高度设置为和TableView的frame高度一致,此时系统自带的isPagingEnabled就可以直接正常工作,无需写额外代理逻辑,适配不同屏幕尺寸的兼容性也更好。
仅需要修改两处代码即可:

  • 保持tableView.isPagingEnabled = true配置不变
  • 将heightForRowAt的返回值修改为tableView.bounds.height

内容的提问来源于stack exchange,提问作者ayoub

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 15:27:03