UIView.animate 和完成问题

Posted

技术标签:

【中文标题】UIView.animate 和完成问题【英文标题】:Trouble with UIView.animate and completion 【发布时间】:2018-02-05 22:50:58 【问题描述】:

我遇到了 UIView.animate 的问题。

我想要的功能(看起来)很简单:有一个按钮,当你按住它时,整个屏幕会慢慢地被底部的不同颜色填充(通过一个名为 bar 的 UIView 向上移动到顶部来实现,最终填满整个屏幕)。当栏到达顶部时,背景将其颜色更改为栏的颜色,并且栏移回其原始状态,从视图中隐藏并更改其颜色。当人在栏到达顶部之前释放按钮时,栏会很快再次向下移动。

现在我已经解决了如下:

  @IBAction func buttonPressed(_ sender: Any)         
    UIView.animate(withDuration: 3, animations: 
        self.bar.frame.origin.y = 0
    , completion: (finished: Bool) in
        if self.bar.frame.origin.y == 0 

            self.backColor = self.barColor
            self.view.backgroundColor = UIColor(rgb: self.colors[self.backColor])

            self.changeBarColor()
            self.bar.backgroundColor = UIColor(rgb: self.colors[self.barColor])

            self.bar.frame.origin.y = self.view.frame.size.height

        
    )




@IBAction func buttonReleased(_ sender: Any) 

    UIView.animate(withDuration: 0.5, animations: 
            self.bar.frame.origin.y = self.view.frame.size.height
    )

当用户在原始动画的 3 秒结束前松开按钮并再次按下时,就会出现问题。突然,完成块内的所有内容都被执行。我尝试使用 if 语句来缓解问题,但这似乎不起作用。

我认为需要发生的是,当用户在第一个动画完成之前释放按钮时,需要取消动画。有人能指出我正确的方向吗?

我附上了一个视频来说明这个问题:

Video of Problem

【问题讨论】:

看我的回答...... 【参考方案1】:

您面临的问题是因为之前的动画仍在执行。关键是去掉之前的动画。

@IBAction func buttonPressed(_ sender: Any)      

if self.bar.frame.origin.y != self.view.frame.size.height

    view.layer.removeAllAnimations()
    UIView.animate(withDuration: 3, animations: 
        self.bar.frame.origin.y = 0
    , completion: (finished: Bool) in
         self.backColor = self.barColor
         self.view.backgroundColor = UIColor(rgb: self.colors[self.backColor])
         self.changeBarColor()
         self.bar.backgroundColor = UIColor(rgb: self.colors[self.barColor])
         self.bar.frame.origin.y = self.view.frame.size.height
    )

else
   
    UIView.animate(withDuration: 3, animations: 
        self.bar.frame.origin.y = 0
    , completion: (finished: Bool) in
        if self.bar.frame.origin.y == 0 

            self.backColor = self.barColor
            self.view.backgroundColor = UIColor(rgb: self.colors[self.backColor])

            self.changeBarColor()
            self.bar.backgroundColor = UIColor(rgb: self.colors[self.barColor])

            self.bar.frame.origin.y = self.view.frame.size.height

        
    )



@IBAction func buttonReleased(_ sender: Any) 
    view.layer.removeAllAnimations()
    UIView.animate(withDuration: 0.5, animations:                 
            self.bar.frame.origin.y = self.view.frame.size.height
    )

【讨论】:

不幸的是,这似乎并没有解决问题。我不明白为什么“完成”部分中的代码会被执行,尽管动画被第二个动画打断了。 @Bela :为此,您需要在触发新动画之前删除之前的动画。除非你这样做,否则之前的动画将继续执行。 @Bela :如果用户在上一个动画完成之前按下按钮,理想的场景是什么?您提到的不同视图的框架或位置应该是什么? 理想情况下,栏会转身并再次上升,就像用户过早释放按钮后栏开始下降一样。如果它只是下降就可以了,因为它非常快。 “已完成”部分中的代码仅应在栏真正到达顶部时执行。 不,我收到错误:“二元运算符 '!=' 不能应用于 'CGPoint' 和 'CGFloat' 类型的操作数”

以上是关于UIView.animate 和完成问题的主要内容,如果未能解决你的问题,请参考以下文章

UIView animate withDuration 不会在 iOS 9.3.5 上调用完成处理程序

UIView.animate() :我需要在动画块中对 self 进行弱引用吗? [复制]

在 awakeFromNib 上调用 UIView animate withDuration 不会执行动画

视图框架的 UIView.animate 问题

UIView,动画,完成块,UIAlertView

在动画完成之前调用 UIView 动画完成