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

为何UIView与键盘弹出同步动画不生效?(Xcode12纯代码)

问题:UIView随键盘弹出上移无动画效果,frame已更新但模拟器无变化

我尝试实现UIView随键盘弹出同步上移,确保输入框在键盘弹出时仍显示在可视区域。但代码中视图的frame已更新,模拟器却无动画效果。使用Xcode12纯代码开发(无Storyboard),该函数在键盘弹出通知触发时执行:

打印输出

showing keyboard
begin
(0.0, 528.96, 375.0, 88.16)
end
(0.0, 528.96, 375.0, 88.16)
this should be changed
(0.0, 237.96000000000004, 375.0, 379.15999999999997)
end
(0.0, 237.96000000000004, 375.0, 379.15999999999997)

原代码

@objc private func keyboardWillShow(notification: NSNotification) {
    print("showing keyboard")

    let userInfo: NSDictionary = notification.userInfo! as NSDictionary
    let keyboardFrame: NSValue = userInfo.value(forKey: UIResponder.keyboardFrameEndUserInfoKey) as! NSValue
    let keyboardRectangle = keyboardFrame.cgRectValue
    let keyboardHeight = keyboardRectangle.height
    let commentViewSize: CGFloat = view.height/7

    print("begin")
    print(commentFieldView.frame)

    UIView.animate(withDuration: 0.1, delay: 0, animations: { [weak self] in
        guard let strongSelf = self else {
            return
        }

        DispatchQueue.main.async {
            strongSelf.commentFieldView.frame = CGRect(x: 0, y: strongSelf.view.height - commentViewSize - keyboardHeight, width: strongSelf.view.width, height: commentViewSize + keyboardHeight)

            strongSelf.profilePic.frame = CGRect(x: strongSelf.commentFieldView.left + 15, y: strongSelf.commentFieldView.height/5, width: 100, height: 100)

            print("this should be changed")
            print(strongSelf.commentFieldView.frame)
        }
    }) { _ in
        print("end")
        print(self.commentFieldView.frame)
    }

    print("end")
    print(self.commentFieldView.frame)
}

解决方案

问题根源

  1. 动画上下文被破坏:UIView.animate的闭包本身就在主队列执行,嵌套DispatchQueue.main.async会让frame更新操作脱离动画上下文,无法触发动画。
  2. 动画时长不合理:手动设置的0.1秒时长过短,几乎无法感知,建议使用键盘通知自带的动画时长,和系统键盘动画保持同步。

修复后的代码

@objc private func keyboardWillShow(notification: NSNotification) {
    print("showing keyboard")

    guard let userInfo = notification.userInfo else { return }
    // 获取键盘最终高度
    let keyboardFrame = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue
    let keyboardHeight = keyboardFrame.cgRectValue.height
    let commentViewSize: CGFloat = view.height/7

    print("begin")
    print(commentFieldView.frame)

    // 获取系统键盘的动画时长
    let animationDuration = userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as! TimeInterval

    UIView.animate(withDuration: animationDuration) { [weak self] in
        guard let strongSelf = self else { return }
        // 直接在动画闭包内更新frame,无需嵌套主队列
        strongSelf.commentFieldView.frame = CGRect(
            x: 0,
            y: strongSelf.view.height - commentViewSize - keyboardHeight,
            width: strongSelf.view.width,
            height: commentViewSize + keyboardHeight
        )

        strongSelf.profilePic.frame = CGRect(
            x: strongSelf.commentFieldView.left + 15,
            y: strongSelf.commentFieldView.height/5,
            width: 100,
            height: 100
        )

        print("this should be changed")
        print(strongSelf.commentFieldView.frame)
    } completion: { _ in
        print("end")
        print(self?.commentFieldView.frame ?? .zero)
    }

    print("end")
    print(self.commentFieldView.frame)
}

额外提示

  • 如果视图使用Auto Layout约束,直接修改frame可能和约束冲突,建议通过修改约束的constant值实现上移动画,这是更稳妥的方案。
  • 记得在viewDidLoad中正确注册键盘通知:
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(notification:)), name: UIResponder.keyboardWillHideNotification, object: nil)

内容的提问来源于stack exchange,提问作者Car Lord VR

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 03:40:21