push页面返回后键盘高度异常导致collection view布局裁剪问题如何解决
问题产生原因
- 你计算键盘高度时没有排除设备底部安全区域(Home Indicator区域)的高度,系统返回的
keyboardFrameEnd是相对于整个屏幕的坐标,天然包含了底部安全区的高度,直接计算和listView的交集时,会把安全区高度也算进键盘高度里,正好对应你遇到的336和293的差值。 - push新页面返回时,视图布局周期和键盘通知的触发顺序错位,你拿到键盘frame做坐标转换时,当前view的布局还没完成,导致交集高度计算异常。
- 缺少
keyboardWillHide通知的监听,页面返回时旧约束没有及时重置,和新的键盘通知触发的约束更新冲突,导致高度计算叠加。
规范解决方案
1. 修正键盘高度计算逻辑,排除安全区域影响
计算偏移量时主动减去当前view的底部安全区高度,同时让约束更新和键盘弹出动画同步,提升流畅度:
@objc private func keyboardWillShow(notification: NSNotification) { guard let userInfo = notification.userInfo, let keyboardFrameEnd = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue else { return } let keyboardRect = keyboardFrameEnd.cgRectValue // 转换键盘frame到当前view的坐标系 let convertedRect = view.convert(keyboardRect, from: view.window) // 排除底部安全区高度,得到实际的键盘可用高度 let validKeyboardHeight = convertedRect.height - view.safeAreaInsets.bottom guard validKeyboardHeight > 0 else { return } // 用updateConstraints替代remakeConstraints,避免修改其他约束 listView.snp.updateConstraints { make in make.bottom.equalTo(-validKeyboardHeight) } // 同步键盘动画时长,避免生硬的约束跳转 if let duration = userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double, let curve = userInfo[UIResponder.keyboardAnimationCurveUserInfoKey] as? UInt { UIView.animate(withDuration: duration, delay: 0, options: .init(rawValue: curve)) { self.view.layoutIfNeeded() } } else { view.layoutIfNeeded() } }
2. 补充键盘隐藏的监听处理
@objc private func keyboardWillHide(notification: NSNotification) { listView.snp.updateConstraints { make in make.bottom.equalTo(0) } // 同步键盘收起动画 guard let userInfo = notification.userInfo, let duration = userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double, let curve = userInfo[UIResponder.keyboardAnimationCurveUserInfoKey] as? UInt else { view.layoutIfNeeded() return } UIView.animate(withDuration: duration, delay: 0, options: .init(rawValue: curve)) { self.view.layoutIfNeeded() } }
3. 调整通知的添加移除时机
在页面即将显示时添加监听,页面即将消失时移除监听,避免页面不可见时收到无效的键盘通知:
override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil) } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillShowNotification, object: nil) NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil) }
内容的提问来源于stack exchange,提问作者user3492121
相关产品推荐
相关产品推荐

