在didMoveToSuperview中调用的UIView.animate意外影响所有子视图

时间:2019-04-17 08:42:50

标签: ios swift animation

我正在使用自定义UIView。我使它们都能正常工作,但是我的设计要求规定视图的某些部分应在加载时进行动画处理。

我的视图是通过以下方式设置的,并且我选择设置约束动画: UIView layout

所以我在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)
}

我什么也没做。动画本身仅影响箭头图像视图的前导约束。正如预期的那样。如下图所示,我在与用户互动时启动动画时可以验证这一点。

Arrow animation on user interaction

现在,问题是,从didMoveToSuperview()内部调用时,动画会以某种方式影响我的自定义UIView的所有子视图...

Animation on didMoveToSuperview

我在做什么错了?

3 个答案:

答案 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一起使用的信息。