点击Return后键盘高度变化,ScrollView滚动异常问题求助
我太懂这种反复操作后布局掉链子的烦恼了!你遇到的问题大概率是键盘收起时没正确重置ScrollView的布局参数,或者滚动逻辑有遗漏,咱们一步步来修复:
一、先补全键盘收起时的重置逻辑
你大概率只处理了键盘弹出时的contentInset设置,却没在键盘收起时把ScrollView的参数还原回去,这会导致第二次触发时布局计算混乱。先补上键盘收起的处理方法:
@objc func keyboardWillBeHidden(_ notification: Notification) { guard let userInfo = notification.userInfo else { return } let animationDuration = userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double ?? 0.25 UIView.animate(withDuration: animationDuration) { // 重置contentInset和滚动指示器的Insets为初始值 self.scrollView.contentInset = .zero self.scrollView.scrollIndicatorInsets = .zero // 可选:如果需要让页面回到初始位置,加上这行 self.scrollView.contentOffset = .zero } }
别忘了在注册通知的时候把这个方法加上:
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillBeHidden(_:)), name: UIResponder.keyboardWillHideNotification, object: nil)
二、优化键盘弹出时的滚动计算逻辑
有时候第一次滚动后,ScrollView的contentOffset没有正确重置,第二次弹出时就会计算错误。可以主动计算TextField需要的滚动偏移量,确保它完全显示在键盘上方:
@objc func keyboardWasShown(_ notification: Notification) { guard let userInfo = notification.userInfo else { return } let keyboardFrame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue ?? .zero let animationDuration = userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double ?? 0.25 let keyboardHeight = keyboardFrame.height // 计算TextField在ScrollView坐标系中的位置 let textFieldFrameInScroll = scrollView.convert(bottomTextField.frame, from: bottomTextField.superview) // 算出需要滚动的偏移量,确保TextField底部不被键盘挡住 let requiredOffset = textFieldFrameInScroll.maxY - (scrollView.bounds.height - keyboardHeight) UIView.animate(withDuration: animationDuration) { self.scrollView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: keyboardHeight, right: 0) self.scrollView.scrollIndicatorInsets = self.scrollView.contentInset // 如果需要滚动,就主动调整contentOffset if requiredOffset > 0 { self.scrollView.contentOffset = CGPoint(x: 0, y: requiredOffset) } } }
三、额外的避坑提示
- 记得在页面销毁时移除通知观察者,避免内存泄漏:
deinit { NotificationCenter.default.removeObserver(self) }
- 建议把键盘弹出的监听通知换成
UIResponder.keyboardWillShowNotification,用willShow的时机比didShow更提前,能避免布局延迟导致的滚动不及时。 - 如果你的ScrollView用了AutoLayout,不要给它的底部设置固定到父视图底部的约束,留足弹性空间才不会和
contentInset的设置冲突。
这样调整后,第二次点击底部TextField时,ScrollView应该能正确计算滚动幅度,确保TextField不会被键盘遮挡了。
内容的提问来源于stack exchange,提问作者wm.p1us




