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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 20:39:01