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

iOS设备旋转且键盘弹出时,自定义动画时长被系统覆盖如何解决?

解决iOS键盘旋转时自定义动画时长被系统覆盖的问题

这个坑我之前踩过!系统在UIKeyboardWillChangeFrame通知的回调里,其实已经处于一个自带的动画上下文当中了,咱们直接写的动画会被这个上下文的参数(比如时长、曲线)强制覆盖,所以自定义时长根本不生效。下面给你几个经过验证的解决方案:

方案1:把自定义动画放到下一个RunLoop周期

系统的键盘动画是在当前RunLoop执行的,咱们用DispatchQueue.main.async把自己的动画代码推迟到下一个RunLoop,就能避开系统的动画上下文,完全用自己的参数控制动画。

代码示例:

NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillChangeFrameNotification, 
                                       object: nil, 
                                       queue: .main) { [weak self] notification in
    guard let userInfo = notification.userInfo,
          let endFrame = userInfo[UIKeyboardFrameEndUserInfoKey] as? CGRect else { return }
    
    // 计算需要调整的约束值(这里以底部约束为例)
    let bottomInset = UIScreen.main.bounds.height - endFrame.origin.y
    self?.contentBottomConstraint.constant = bottomInset
    
    // 推迟到下一个RunLoop执行自定义动画
    DispatchQueue.main.async {
        UIView.animate(withDuration: 0.8, // 这里写你想要的自定义时长
                       delay: 0,
                       options: .curveEaseInOut) {
            self?.view.layoutIfNeeded()
        }
    }
}

方案2:临时禁用系统动画,再执行自定义动画

先强制关闭系统的动画开关,立即更新约束(无动画),然后再开启动画开关,执行咱们自己的过渡动画。这种方式可以完全摆脱系统动画的影响。

代码示例:

NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillChangeFrameNotification, 
                                       object: nil, 
                                       queue: .main) { [weak self] notification in
    guard let userInfo = notification.userInfo,
          let endFrame = userInfo[UIKeyboardFrameEndUserInfoKey] as? CGRect else { return }
    
    let bottomInset = UIScreen.main.bounds.height - endFrame.origin.y
    self?.contentBottomConstraint.constant = bottomInset
    
    // 临时禁用系统动画,立即更新布局
    UIView.setAnimationsEnabled(false)
    self?.view.layoutIfNeeded()
    UIView.setAnimationsEnabled(true)
    
    // 执行自定义时长的动画
    UIView.animate(withDuration: 0.8) {
        self?.view.layoutIfNeeded()
    }
}

方案3:使用UIViewPropertyAnimator(更灵活的控制)

UIViewPropertyAnimator是苹果推出的更强大的动画控制类,它不受系统默认动画上下文的影响,还能支持暂停、倒播等高级操作,适合需要精细控制动画的场景。

代码示例:

NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillChangeFrameNotification, 
                                       object: nil, 
                                       queue: .main) { [weak self] notification in
    guard let self = self,
          let userInfo = notification.userInfo,
          let endFrame = userInfo[UIKeyboardFrameEndUserInfoKey] as? CGRect else { return }
    
    let bottomInset = UIScreen.main.bounds.height - endFrame.origin.y
    self.contentBottomConstraint.constant = bottomInset
    
    // 初始化自定义时长的动画器
    let animator = UIViewPropertyAnimator(duration: 0.8, curve: .easeInOut) {
        self.view.layoutIfNeeded()
    }
    animator.startAnimation()
}

额外注意事项

  • 一定要在闭包里用weak self,避免因为通知持有导致的内存泄漏。
  • 如果同时处理设备旋转和键盘状态,建议提前记录当前键盘的显示状态,旋转完成后再重新触发动画,避免状态混乱。
  • 不同iOS版本可能有细微差异,建议在目标版本上多做测试,比如iOS 15+和iOS 13的动画上下文处理可能略有不同。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 04:25:04