UIViewPropertyAnimator 自动布局完成问题
Posted
技术标签:
【中文标题】UIViewPropertyAnimator 自动布局完成问题【英文标题】:UIViewPropertyAnimator AutoLayout Completion Issue 【发布时间】:2018-07-23 19:15:20 【问题描述】:我正在使用 UIViewPropertyAnimator 运行数组交互式动画,我遇到的一个问题是,每当我反转动画时,我都无法再次向前运行动画。
我使用三个函数与平移手势识别器一起处理动画。
private var runningAnimations = [UIViewPropertyAnimator]()
private func startInteractiveTransition(gestureRecognizer: UIPanGestureRecognizer, state: ForegroundState, duration: TimeInterval)
if runningAnimations.isEmpty
animateTransitionIfNeeded(gestureRecognizer: gestureRecognizer, state: state, duration: duration)
for animator in runningAnimations
animator.pauseAnimation()
animationProgressWhenInterrupted = animator.fractionComplete
private func animateTransitionIfNeeded(gestureRecognizer: UIPanGestureRecognizer, state: ForegroundState, duration: TimeInterval)
guard runningAnimations.isEmpty else
return
let frameAnimator = UIViewPropertyAnimator(duration: duration, dampingRatio: 1)
switch state
case .expanded:
// change frame
case .collapsed:
// change frame
frameAnimator.isReversed = false
frameAnimator.addCompletion _ in
print("remove all animations")
self.runningAnimations.removeAll()
self.runningAnimations.append(frameAnimator)
for animator in runningAnimations
animator.startAnimation()
private func updateInteractiveTransition(gestureRecognizer: UIPanGestureRecognizer, fractionComplete: CGFloat)
if runningAnimations.isEmpty
print("empty")
for animator in runningAnimations
animator.fractionComplete = fractionComplete + animationProgressWhenInterrupted
我注意到在我反转动画然后调用 animateTransitionIfNeeded 后,frameAnimator 被附加到正在运行的动画中,但是当我立即调用 updateInteractiveTransition 并检查 runningAnimations 时,它是空的。
所以我被引导相信这可能与 swift 如何处理内存或 UIViewAnimating 如何完成动画有关。
有什么建议吗?
【问题讨论】:
【参考方案1】:我开始意识到 UIViewPropertyAnimator 在反转时如何处理布局约束的问题。 我在网上或官方文档中找不到太多关于它的细节,但我确实发现这很有帮助。
Animator 只是将视图动画化到新帧中。但是,无论是否反转,无论您是否反转了动画师,新的约束仍然有效。因此,在动画师完成后,如果稍后自动布局再次布置视图,我希望视图会进入当前活动约束设置的位置。简单地说:动画师动画帧变化,而不是约束本身。这意味着反转动画师会反转帧,但不会反转约束 - 一旦自动布局执行另一个布局循环,它们就会再次应用。
像往常一样设置约束并调用view.layoutIfNeeded()
animator = UIViewPropertyAnimator(duration: duration, dampingRatio: 1)
[unowned self] in
switch state
case .expanded:
self.constraintA.isActive = false
self.constraintB.isActive = true
self.view.layoutIfNeeded()
case .collapsed:
self.constraintB.isActive = false
self.constraintA.isActive = true
self.view.layoutIfNeeded()
现在,由于我们的动画师具有反转能力,我们添加了一个完成处理程序,以确保正确的约束在完成时通过使用结束位置处于活动状态。
animator.addCompletion [weak self] (position) in
if position == .start
switch state
case .collapsed:
self?.constraintA.isActive = false
self?.constraintB.isActive = true
self?.view.layoutIfNeeded()
case .expanded:
self?.constraintA.isActive = false
self?.constraintB.isActive = true
self?.view.layoutIfNeeded()
【讨论】:
我遇到了与您完全相同的问题(也停用了一个约束并将其替换为另一个)但是此解决方案对我不起作用。你能提供你的整个动画代码吗?谢谢 @dvdblk 问题可能在于您的完成动画。在调用 continue 动画函数之前,请确保检查完成百分比并激活/停用正确的约束 @dvdblk 还会在动画师启动时检查您的动画师分数,确保它为零。我遇到了一个问题,有时它从 1 开始。我相信这甚至可能是由于重用动画师造成的。【参考方案2】:动画师对视图的动画属性进行操作,例如 frame、center、alpha 和 transform 属性,根据您提供的块创建所需的动画。
这是文档的关键部分。 您可以正确设置动画: frame、center、alpha 和 transform,因此您将无法正确地为 NSConstraints 设置动画。
您应该修改 addAnimations
块内的视图框架
【讨论】:
UIViewPropertyAnimator 绝对能够使用layoutIfNeeded()
在 NSLayoutConstraints 上执行动画以上是关于UIViewPropertyAnimator 自动布局完成问题的主要内容,如果未能解决你的问题,请参考以下文章
为啥在 UIViewPropertyAnimator 中使用“unowned”