将带inputAccessoryView的UIViewController推入导航栈时动画闪烁异常
这个闪烁问题是UIKit在push动画过程中的常见行为:动画执行时,新控制器的inputAccessoryView会被临时附加到当前窗口,导致在父控制器界面短暂显示,动画结束后才会正确关联到新控制器的视图层级,从而产生闪烁滞后的现象。
解决方案:延迟成为第一响应者
核心思路是避免在push动画完成前让ChatViewController成为第一响应者,等动画结束后再触发inputAccessoryView的加载显示。
修改后的ChatViewController代码:
class ChatViewController: UIViewController { let accessoryView = UIView() private var allowFirstResponder = false override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .white // 用AutoLayout替代frame设置尺寸,布局更稳定 accessoryView.translatesAutoresizingMaskIntoConstraints = false accessoryView.backgroundColor = .red NSLayoutConstraint.activate([ accessoryView.heightAnchor.constraint(equalToConstant: 80) ]) } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) // 动画完成后允许成为第一响应者并触发 allowFirstResponder = true becomeFirstResponder() } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) // 返回时取消第一响应者状态,避免异常 resignFirstResponder() allowFirstResponder = false } override var canBecomeFirstResponder: Bool { allowFirstResponder } override var inputAccessoryView: UIView? { accessoryView } }
补充方案:通过导航控制器代理控制
如果需要更精准控制时机,可以在父控制器中设置UINavigationControllerDelegate,在push动画完全结束后再让ChatViewController成为第一响应者:
// 父控制器中实现代理 extension ParentViewController: UINavigationControllerDelegate { func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) { guard let chatVC = viewController as? ChatViewController else { return } chatVC.becomeFirstResponder() } } // 此时ChatViewController的canBecomeFirstResponder直接返回true即可 class ChatViewController: UIViewController { let accessoryView = UIView() override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .white accessoryView.translatesAutoresizingMaskIntoConstraints = false accessoryView.backgroundColor = .red NSLayoutConstraint.activate([ accessoryView.heightAnchor.constraint(equalToConstant: 80) ]) } override var canBecomeFirstResponder: Bool { true } override var inputAccessoryView: UIView? { accessoryView } }
关键注意点
- 尽量使用AutoLayout约束inputAccessoryView的尺寸,避免frame布局在视图层级变化时出现的位置偏差
- 在视图消失时务必调用
resignFirstResponder(),防止返回父控制器时出现残留的inputAccessoryView
内容的提问来源于stack exchange,提问作者dfmuir
相关产品推荐
相关产品推荐

