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

UITableView设置较大bottom contentInset后键盘弹出时滚动位置异常

问题原因

UITableView 继承自 UIScrollView,系统内置了默认行为:当滚动视图内部的 UITextField / UITextView 成为第一响应者唤起键盘时,会自动计算输入控件在窗口中的可见位置,如果判断输入控件会被键盘遮挡、且滚动视图有足够的滚动余量,就会自动调整 contentOffset 将输入控件滚动到可见区域。
你设置了较大的 contentInset.bottom 后,滚动视图的可滚动范围(contentSize.height + 上下contentInset总和)远大于自身 frame 高度,系统判定有足够的滚动空间,就触发了自动滚动逻辑,这就是异常现象的成因。

解决方案(不使用 contentInsetAdjustmentBehavior = .never 前提下)

方案1:轻量拦截系统自动滚动

监听键盘弹出通知,在系统执行默认滚动逻辑后强制还原当前contentOffset,覆盖系统的自动滚动操作:

override func viewDidLoad() {
    super.viewDidLoad()
    // 原有逻辑保持不变
    // 添加键盘监听
    NotificationCenter.default.addObserver(self, selector: #selector(lockTableOffset), name: UIResponder.keyboardWillShowNotification, object: nil)
}

@objc private func lockTableOffset() {
    let currentOffset = tableView.contentOffset
    // 异步操作会在系统默认滚动逻辑执行后触发,直接重置offset
    DispatchQueue.main.async { [weak self] in
        self?.tableView.setContentOffset(currentOffset, animated: false)
    }
}

// 移除通知避免内存泄漏
deinit {
    NotificationCenter.default.removeObserver(self)
}

方案2:精准控制滚动拦截

如果需要区分用户手动滚动和系统自动滚动,避免影响正常交互,可以自定义UITableView子类实现拦截:

// 自定义TableView类
class NoAutoScrollTableView: UITableView {
    // 标记是否禁止系统自动滚动
    var disableSystemAutoScroll = false
    
    override func setContentOffset(_ contentOffset: CGPoint, animated: Bool) {
        // 仅拦截非用户主动触发的滚动,用户手动滑动、甩动不受影响
        if disableSystemAutoScroll && !isTracking && !isDragging && !isDecelerating {
            super.setContentOffset(self.contentOffset, animated: false)
            return
        }
        super.setContentOffset(contentOffset, animated: animated)
    }
}

在控制器中配合输入框代理控制标记位即可:

// 替换原有tableView的类型
let tableView = NoAutoScrollTableView()

// 在cellForRowAt方法中给textField设置代理
textField.delegate = self

// 实现UITextFieldDelegate协议
extension TestViewController: UITextFieldDelegate {
    func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
        tableView.disableSystemAutoScroll = true
        return true
    }
    
    func textFieldDidEndEditing(_ textField: UITextField) {
        tableView.disableSystemAutoScroll = false
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 09:24:03