UIView 动画在转换到新视图之前快速恢复到原始状态
Posted
技术标签:
【中文标题】UIView 动画在转换到新视图之前快速恢复到原始状态【英文标题】:UIView animation snaps back to original state before transitioning to a new view 【发布时间】:2019-10-03 13:44:01 【问题描述】:我有一些 UIButtons 我正在无限期地制作动画。这些按钮都添加了 3 个子层,每个子层都有自己的动画。我正在viewDidAppear
上初始化这些动画,效果很好——它们淡入并开始旋转。问题是当我转换到一个新视图时,动画似乎“快速”回到它们的初始状态,然后在转换发生之前回到其他状态。我已经尝试显式删除 viewWillDisappear 上的所有动画,甚至尝试隐藏整个 UIButton 本身,但似乎没有什么能阻止这种奇怪的捕捉行为发生。
这是正在发生的事情的 gif 图像(这是我在两个视图之间来回转换):
func animateRotation()
// Gets called on viewDidAppear
let rotationRight: CABasicAnimation = CABasicAnimation(keyPath: "transform.rotation.z")
rotationRight.toValue = Double.pi * 2
rotationRight.duration = 4
rotationRight.isCumulative = true
rotationRight.repeatCount = Float.greatestFiniteMagnitude
rotationRight.isRemovedOnCompletion = false
rotationRight.fillMode = .forwards
let rotationLeft: CABasicAnimation = CABasicAnimation(keyPath: "transform.rotation.z")
rotationLeft.toValue = Double.pi * -2
rotationLeft.duration = 3
rotationLeft.isCumulative = true
rotationLeft.repeatCount = Float.greatestFiniteMagnitude
rotationLeft.isRemovedOnCompletion = false
rotationLeft.fillMode = .forwards
let circleImage1 = UIImage(named: "circle_1")?.cgImage
circleLayer1.frame = self.bounds
circleLayer1.contents = circleImage1
circleLayer1.add(rotationRight, forKey: "rotationAnimation")
layer.addSublayer(circleLayer1)
let circleImage2 = UIImage(named: "circle_2")?.cgImage
circleLayer2.frame = self.bounds
circleLayer2.contents = circleImage2
circleLayer2.add(rotationLeft, forKey: "rotationAnimation")
layer.addSublayer(circleLayer2)
let circleImage3 = UIImage(named: "circle_3")?.cgImage
circleLayer3.frame = self.bounds
circleLayer3.contents = circleImage3
circleLayer3.add(rotationRight, forKey: "rotationAnimation")
layer.addSublayer(circleLayer3)
我认为这样简单的事情会在它知道按钮消失后立即将其完全隐藏:
override func viewWillDisappear(_ animated: Bool)
animatedButton.isHidden = true
有趣的是,如果我让它运行几分钟,这似乎就不会发生了。这告诉我这可能是某种竞争条件。只是不确定那场比赛可能是什么......
【问题讨论】:
过渡到新视图时,您的意思是转到新屏幕并返回吗?你试过在 ViewDidLoad() 中调用 animateRotation() 吗?是否有必要在 viewDidAppear() 中? 用动画进入视图时效果很好。我看到的奇怪行为是立即在离开屏幕并激活动画。所以我点击按钮离开屏幕,动画闪烁,然后屏幕切换到下一个视图。 你能显示点击按钮时触发的代码吗?试图了解您的视图控制器的结构。所以当屏幕加载时动画总是可见的?显示您点击按钮的 gif 图像可能会很有用,这样我就可以了解您的视图的外观和工作方式。动画似乎同时运行了多次。 @AlecSanger “有趣的是,如果我让它运行几分钟,这似乎就不会发生了。”我想知道这是否与动画的“.duration”属性有关。也许尝试将持续时间设置为 15 秒,看看错误是否发生在 15 秒之前而不是之后。 当按钮被点击时实际上什么都没有发生——你可以考虑将这些普通的 UIViews 应用为子层的图像。将动画设置为仅运行一次时,旋转会正确停止在最后的静止位置(1 个完整旋转)。当导航离开屏幕时,没有闪烁,因为闪烁在当前动画位置和图层的原始位置之间移动。如果我让动画完成,这些都是一样的。 【参考方案1】:当您使用 UIView 动画集时,它们会将实际状态设置为最终状态,然后启动动画,即:
UIView.animate(withDuration: 1) view.alpha = 0
如果您在动画开始后立即检查 alpha,它已经是 0。
这是 UIView 为您提供的便利,但 CALayer 没有。当您设置 CALayer 动画时,您只是在设置动画值,而不是变量的实际值,因此当动画完成时,图层会恢复到其原始值。在动画中间检查图层值,你会看到真实的值没有改变;只有表示层中的动画值发生了变化。
如果你想复制 UIView 行为,你需要在动画开始时设置实际的最终值而不是图层,或者在动画结束时使用委托来设置它。
【讨论】:
你所说的一切都完全有道理,我很确定你的建议会解决问题。但是,我继续使用 UIView.animate + self.transform 将我的 3 个单独动画子层替换为单个旋转 UIButton,并在其上应用单个图像,并且我仍然看到相同的行为。这告诉我这与 CALayer 无关。以上是关于UIView 动画在转换到新视图之前快速恢复到原始状态的主要内容,如果未能解决你的问题,请参考以下文章