UITextView唤起键盘时滚动视图上移失效问题排查与解决
UITextView唤起键盘时滚动视图不偏移的问题解决
先聊聊UITextField和UITextView唤起键盘的核心差异
这俩控件在键盘唤起时的行为差异主要源于它们的本质:
- UITextField是纯输入控件,本身没有滚动能力。当它成为第一响应者时,系统会自动检测父级UIScrollView,并尝试调整scrollView的contentOffset,确保输入框不被键盘遮挡(前提是scrollView的相关配置正常)。
- UITextView是
UIScrollView的子类,自带滚动功能。默认情况下,系统会优先处理UITextView自身的滚动逻辑,而不会主动去调整父级ScrollView的位置。另外,它的automaticallyAdjustsScrollIndicatorInsets等属性也会干扰父视图的调整行为。
你的问题分析与解决
你提到keyboardWillShow方法确实被调用了,contentInset设置也和UITextField一致,但视图没上移——核心原因是你只设置了contentInset,但没有主动让父ScrollView滚动到UITextView可见的位置,再加上UITextView自身的滚动特性干扰了系统的自动调整。
下面是具体的修复步骤:
1. 调整UITextView的基础设置(可选但推荐)
如果你的UITextView不需要自身滚动(比如只是多行输入,内容不会超过控件高度),可以关闭它的滚动功能,避免系统优先处理它的滚动:
override func viewDidLoad() { super.viewDidLoad() // 关闭TextView自身滚动 textView.isScrollEnabled = false // iOS11+ 关闭scrollView的自动contentInset调整,避免和我们手动设置冲突 if #available(iOS 11.0, *) { scrollView.contentInsetAdjustmentBehavior = .never } }
2. 修改键盘监听方法,补充关键逻辑
更新你的keyboardWillShow和keyboardWillHide方法,确保同步设置scrollIndicatorInsets,并主动调整contentOffset让当前输入控件可见:
func keyboardWillShow(notification: NSNotification) { guard let endFrame = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue else { return } var keyboardHeight = view.bounds.height - endFrame.origin.y if #available(iOS 11, *) { if keyboardHeight > 0 { keyboardHeight -= view.safeAreaInsets.bottom } } else { keyboardHeight = (notification.userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue.size.height } // 同步设置contentInset和scrollIndicatorInsets let inset = UIEdgeInsets(top: 0, left: 0, bottom: keyboardHeight, right: 0) scrollView.contentInset = inset scrollView.scrollIndicatorInsets = inset // 主动滚动到当前第一响应者的位置,确保不被键盘遮挡 if let activeInputView = view.firstResponder as? UIView { let targetRect = scrollView.convert(activeInputView.frame, from: activeInputView.superview) scrollView.scrollRectToVisible(targetRect, animated: true) } // 更新底部约束 viewBottom.constant = keyboardHeight view.layoutIfNeeded() } func keyboardWillHide(notification: NSNotification) { let inset = UIEdgeInsets.zero scrollView.contentInset = inset scrollView.scrollIndicatorInsets = inset viewBottom.constant = 0 view.layoutIfNeeded() }
3. 额外注意点
- 如果你的UITextView需要保留自身滚动功能,那就要在它成为第一响应者时,手动计算父ScrollView需要偏移的距离,同时避免两者的滚动逻辑冲突。
- 确保你已经正确注册了键盘通知:
override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) 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) } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) NotificationCenter.default.removeObserver(self) }
这样修改后,UITextView唤起键盘时,父ScrollView应该就能正常上移了。
内容的提问来源于stack exchange,提问作者ava
相关产品推荐
相关产品推荐

