You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

键盘弹出时上移TextField,收起后留下黑条问题

问题原因及解决思路

这问题我之前帮好几个开发者排查过,大概率是这几个常见原因导致的,咱们一个个捋清楚:

1. 监听了错误的键盘收起通知

很多开发者会犯的一个小错误:弹出键盘时用了UIKeyboardWillShowNotification(实时响应),但收起键盘时却用了UIKeyboardDidHideNotification——这个通知是键盘完全消失后才触发的,这时候再调整视图位置,自然会出现“键盘已经下移了,视图还留在上面,直到键盘消失才跳回去”的情况,黑条就是这么来的。

解决办法:把收起的监听换成UIKeyboardWillHideNotification,它会在键盘开始收起的瞬间触发,能让视图和键盘同步动起来。比如代码里的通知注册要改成这样:

// 替换掉原来的DidHide监听
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIKeyboardWillHideNotification, object: nil)

2. 视图动画参数和键盘不匹配

键盘的弹出/收起动画是有系统默认的时长和曲线的,如果你自己写死了动画时长(比如硬编码0.3秒),或者用了默认的动画曲线,就会出现视图和键盘“不同步”的情况,视觉上就会觉得视图滞后。

正确的做法是从键盘通知的userInfo里取出系统自带的动画参数,用这些参数来做视图调整的动画:

@objc func keyboardWillHide(_ notification: Notification) {
    guard let userInfo = notification.userInfo,
          let endFrame = userInfo[UIKeyboardFrameEndUserInfoKey] as? CGRect,
          let duration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as? TimeInterval,
          let curveValue = userInfo[UIKeyboardAnimationCurveUserInfoKey] as? UInt else { return }
    
    let animationOptions = UIView.AnimationOptions(rawValue: curveValue)
    UIView.animate(withDuration: duration, delay: 0, options: animationOptions) {
        // 这里调整视图的位置,比如恢复origin.y到0
        self.view.frame.origin.y = 0
    }
}

3. 用frame调整视图但依赖Auto Layout约束

如果你的页面是用Auto Layout约束布局的,但你却直接修改视图的frame来上移,那系统会在动画过程中或者结束后,强制把视图拉回约束定义的位置,这就会导致中间出现黑条,或者视图突然跳回去的情况。

这种情况应该修改对应的约束(比如底部约束的constant值),然后在动画里调用layoutIfNeeded()

// 假设你有一个IBOutlet连接了视图的底部约束
@IBOutlet weak var bottomConstraint: NSLayoutConstraint!

@objc func keyboardWillHide(_ notification: Notification) {
    guard let userInfo = notification.userInfo,
          let duration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as? TimeInterval,
          let curveValue = userInfo[UIKeyboardAnimationCurveUserInfoKey] as? UInt else { return }
    
    let animationOptions = UIView.AnimationOptions(rawValue: curveValue)
    // 恢复底部约束到初始值
    self.bottomConstraint.constant = 0
    UIView.animate(withDuration: duration, delay: 0, options: animationOptions) {
        self.view.layoutIfNeeded()
    }
}

4. 键盘坐标系转换错误

有时候你获取的键盘frame是相对于屏幕的,而你的视图是相对于window或者自身的坐标系,如果没有做坐标系转换,计算出来的偏移量就会出错,导致收起时视图没有正确跟随键盘下移。

解决办法:把键盘的frame转换到当前视图的坐标系下再计算偏移:

// 在处理通知时,转换键盘frame
let keyboardScreenFrame = userInfo[UIKeyboardFrameEndUserInfoKey] as! CGRect
let keyboardViewFrame = view.convert(keyboardScreenFrame, from: view.window)
// 用转换后的frame来计算需要调整的偏移量

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

火山引擎 最新活动