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

Swift iOS:ScrollView键盘适配异常,首次点击TextView无效

问题解决:首次点击TextView时ScrollView未自动调整位置的修复

问题根源分析

你的代码存在几个关键问题导致首次点击不生效:

  • 使用UIKeyboardFrameBeginUserInfoKey获取键盘尺寸,该Key对应键盘开始显示时的初始位置,而非最终显示完成的位置,导致计算的键盘高度不准确。
  • scrollRectToVisible使用的commentInput.frame是相对于父视图的坐标,未转换为ScrollView内部坐标系,导致滚动目标位置错误。
  • 在keyboardWillHide中禁用了ScrollView的滚动功能,首次点击TextView触发keyboardWillShow时,ScrollView滚动功能的启用时机滞后于滚动操作。

修复步骤及代码调整

1. 替换键盘尺寸获取的Key

将UIKeyboardFrameBeginUserInfoKey替换为UIKeyboardFrameEndUserInfoKey,确保获取的是键盘完全显示后的准确尺寸:

let keyboardSize = (info[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue.size

2. 转换滚动目标的坐标系

把commentInput的frame转换为ScrollView内部的坐标,确保滚动到正确位置:

let targetRect = scrollView.convert(commentInput.frame, from: commentInput.superview)
scrollView.scrollRectToVisible(targetRect, animated: true)

3. 调整ScrollView滚动启用时机

移除keyboardWillHide中scrollView.isScrollEnabled = false的设置,或者在TextView成为第一响应者时提前启用滚动(比如在TextView的didBeginEditing代理方法中设置)。如果必须在键盘隐藏时禁用滚动,可确保在keyboardWillShow中先启用滚动再执行滚动操作,同时延迟滚动操作确保设置生效:

@objc open override func keyboardWillShow(notification: NSNotification) {
    keyboardTapGesture.isEnabled = true
    scrollView.isScrollEnabled = true

    let info = notification.userInfo!
    let keyboardSize = (info[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue.size
    let contentInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: keyboardSize?.height ?? 0.0, right: 0.0)

    scrollView.contentInset = contentInsets
    scrollView.scrollIndicatorInsets = contentInsets

    // 延迟执行滚动确保ScrollView状态已更新
    DispatchQueue.main.async {
        let targetRect = self.scrollView.convert(self.commentInput.frame, from: self.commentInput.superview)
        self.scrollView.scrollRectToVisible(targetRect, animated: true)
    }
}

@objc open override func keyboardWillHide(notification: NSNotification) {
    keyboardTapGesture.isEnabled = false
    scrollView.contentInset = .zero
    scrollView.scrollIndicatorInsets = .zero
    view.endEditing(true)
    // 可选:如果需要在键盘隐藏后禁用滚动,确保下次点击TextView前重新启用
    // 可在TextView的didBeginEditing中设置scrollView.isScrollEnabled = true
    // scrollView.isScrollEnabled = false
}

额外建议

  • 确保已正确注册键盘通知,在viewDidLoad中添加:
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(notification:)), name: UIResponder.keyboardWillHideNotification, object: nil)
  • 在deinit中移除通知,避免内存泄漏:
deinit {
    NotificationCenter.default.removeObserver(self)
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 10:18:31