iOS应用启动时子视图动画失效问题求助
解决UIView入场动画不生效的问题
哥们,我来帮你捋捋这个问题的根源,以及怎么搞定它!
问题出在哪?
你遇到的核心问题是Auto Layout约束和手动修改控件位置的冲突,加上视图生命周期的布局时机问题:
- 当你在
viewWillAppear里修改center.x时,此时Auto Layout还没完成最终布局。在viewWillAppear之后、viewDidAppear之前,系统会自动执行layoutSubviews方法,根据Storyboard里设置的约束重新计算控件位置——这直接把你手动改的center.x给覆盖了! - 等你到
viewDidAppear里执行动画时,控件其实已经被约束拉回了初始位置,动画的起始和结束位置一样,自然看不到效果。甚至你注释掉viewDidAppear后,控件还是保持Storyboard的位置,就是因为约束的优先级远高于你手动设置的属性值。
另外还要确认下:你在viewWillAppear里有没有调用super.viewWillAppear(animated)?如果没调用,也可能导致布局流程异常哦。
正确的解决方案(推荐用Auto Layout动画)
现在iOS开发基本都依赖Auto Layout,所以用约束来做动画才是符合最佳实践的方式,步骤如下:
1. 给控件添加水平约束并关联IBOutlet
打开Storyboard,给你的label、username输入框、password输入框、login按钮分别添加Center X to Superview约束(或者Leading约束,根据你的动画方向调整),然后把这些约束拖到代码里做成IBOutlet:
@IBOutlet weak var labelCenterX: NSLayoutConstraint! @IBOutlet weak var usernameCenterX: NSLayoutConstraint! @IBOutlet weak var passwordCenterX: NSLayoutConstraint! @IBOutlet weak var loginBtnCenterX: NSLayoutConstraint!
2. 在viewWillAppear里设置动画起始状态
这里要修改约束的constant值,把控件移出屏幕,然后立即强制更新布局:
override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) let screenWidth = UIScreen.main.bounds.width // 把所有控件的CenterX约束偏移到屏幕左侧外 labelCenterX.constant = -screenWidth usernameCenterX.constant = -screenWidth passwordCenterX.constant = -screenWidth loginBtnCenterX.constant = -screenWidth // 立即应用约束修改,让控件处于动画起始位置 view.layoutIfNeeded() }
3. 在viewDidAppear里执行动画
通过修改约束的constant回默认值,然后在动画闭包里调用layoutIfNeeded()来触发平滑过渡:
override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) UIView.animate(withDuration: 1.0) { // 把约束改回原位 self.labelCenterX.constant = 0 self.usernameCenterX.constant = 0 self.passwordCenterX.constant = 0 self.loginBtnCenterX.constant = 0 // 让系统在动画过程中更新布局,实现平滑移动 self.view.layoutIfNeeded() } }
备选方案(关闭Auto Layout,不推荐)
如果你的界面特别简单,不需要适配不同屏幕,可以在Storyboard里关闭Auto Layout:选中ViewController,在右侧Attributes Inspector里取消勾选Use Auto Layout。这样你手动修改center.x的操作就不会被约束覆盖了,原来的代码就能生效。不过这种方式在多屏幕适配场景下很容易出问题,所以还是优先用约束动画的方案。
内容的提问来源于stack exchange,提问作者Ahmed Eid
相关产品推荐
相关产品推荐

