我正在使用自定义UIView。我使它们都能正常工作,但是我的设计要求规定视图的某些部分应在加载时进行动画处理。
所以我在UIView.animate()
中叫didMoveToSuperview()
像这样:
override func didMoveToSuperview() {
animateArrow()
}
private func animateArrow() {
UIView.animate(withDuration: 0.3, delay: 0, options: [.curveEaseOut, .autoreverse, .repeat], animations: {
self.arrowLeadingConstraint.constant += 15
self.layoutIfNeeded()
}, completion: nil)
}
我什么也没做。动画本身仅影响箭头图像视图的前导约束。正如预期的那样。如下图所示,我在与用户互动时启动动画时可以验证这一点。
现在,问题是,从didMoveToSuperview()
内部调用时,动画会以某种方式影响我的自定义UIView的所有子视图...
我在做什么错了?
答案 0 :(得分:1)
使用didMoveToSuperview
可能不是最好的主意。在开始动画之前,您需要确保完成屏幕上所有视图的布局,这在didMoveToSuperview
中可能并不总是正确的。
我将动画触发器移动到viewController的viewDidAppear
内或同样位于viewcontroller的didLayoutSubviews
内。
答案 1 :(得分:1)
在此处调用动画代码:
override func draw(_ rect: CGRect) {
super.draw(rect)
animateArrow()
}
或
由@ holex 评论建议:在执行布局遍历之前:
private func animateArrow() {
self.layoutIfNeeded();
self.arrowLeadingConstraint.constant = 31;
UIView.animate(withDuration: 0.3, delay: 0, options: [.curveEaseOut, .autoreverse, .repeat]) {
self.layoutIfNeeded()
}
}
如果动画停止按首页,还可以在init
中添加观察者:
NotificationCenter.default.addObserver(self, selector: #selector(enteredForeground(_:)), name: .UIApplicationWillEnterForeground, object: nil)
答案 2 :(得分:1)
如果您稍微修改一下方法,例如animateArrow()
方法本身就似乎是魔鬼。这个:
private func animateArrow() {
self.layoutIfNeeded()
self.arrowLeadingConstraint.constant = 31 // = 15 + 16 from your original code
UIView.animate(withDuration: 0.3, delay: 0, options: [.curveEaseOut, .autoreverse, .repeat], animations: {
self.layoutIfNeeded()
}, completion: nil)
}
tada ,动画将按预期正常工作。
我的解释在这里可能不是学术性的,但希望对读者有更好的理解是有意义的。
因此,简而言之,当您处理约束时,您将隐式地处理视图与其周围环境之间的一组预定义的关系。这就是为什么您无法成功为单个约束设置动画(您的原始尝试)的原因,因为在这种情况下只有这些关系是可动画的,而不是约束。
因此,您将只能为所有关系的更新制作动画 ,在为布局定义新的约束之后–原则上是在可以一口气为每个受影响的视图创建帧。
如果您对此有兴趣,可以阅读更多有关约束是什么以及评估如何与自动布局from Apple一起使用的信息。