UIViewPropertyAnimator在iOS10和iOS11上反转动画的不同行为。 `isReversed`和`fractionComplete`属性的错误?

时间:2017-09-25 13:40:00

标签: ios uikit ios10 ios11 uiviewpropertyanimator

问题
在iOS10和iOS11上运行相同的代码,我的UIViewPropertyAnimator在更改其.isReversed属性后就有了不同的行为。

在iOS10上一切都很好。动画问题发生在iOS11上

条件
它适用于任何动画,不仅适用于特定的动画,而且可以通过观看动画和代码来验证。 它发生在模拟器和真实设备上。

详情
一旦创建了带有动画的UIViewPropertyAnimator,在其运行期间我只需调用.pauseAnimation()并将.isReversed属性更改为 true 。之后我恢复了动画调用:

continueAnimation(withTimingParameters parameters: UITimingCurveProvider?, durationFactor: CGFloat)

在iOS10上的这一点上,动画平滑地改变了他的诗句,在iOS11上它立即停止并以一点帧滞后反转。

如果在代码中我检查.fractionComplete的值(在我的UIViewPropertyAnimator对象上调用,它会以0.0的百分比从1.0开始以1.0的形式返回动画的完成情况) 就在.continueAnimation(...之后 - 在iOS 10上,它会保留一段时间,就好像动画正在继续,只有在一段时间后跳到他的补充。

- 在iOS 11上,它突然跳起来补充


在文档上有与此相关的非更新,只是UIViewPropertyAnimator的几个新属性但未使用,因为我以iOS10为目标

可能是一个错误,或者我错过了一些东西!?

小更新:刚刚测试过,在iOS 11.0.1和iOS 11.1 beta1上的行为相同

如评论中所链接的那样,只有非线性曲线才会发生这种情况!

3 个答案:

答案 0 :(得分:6)

我一直在争论这个问题很长一段时间,但后来我注意到在iOS 11中添加到scrubsLinearly的{​​{1}}属性:

  

默认为true。使动画师能够线性地或使用动画师的当前时间暂停和擦洗。

请注意,此属性的默认值为UIViewPropertyAnimator,这似乎会导致与使用非线性动画曲线发生冲突。这也可以解释为什么在使用线性定时功能时不存在该问题。

true设置为scrubsLinearly,动画师似乎按预期工作:

false

答案 1 :(得分:1)

  1. 在iOS 11上,fractionComplete在您通过1 - originalFractionComplete反转动画后将被撤消(即animator.isReversed = true)。

  2. 持续时间少于0.1秒的春季动画将立即完成。

  3. 因此,您可能最初想要反转动画运行整个动画持续时间的90%,但在iOS 11上,反转动画的实际持续时间为10%,因为isReversed已更改,并且10%持续时间小于0.1 s,所以动画将立即完成,看起来没有动画发生。

    如何解决?

    对于iOS 10向后兼容性,请在撤消动画之前复制fractionComplete值并将其用于continueAnimation

    e.g。

    let fraction = animator.fractionComplete
    animator.isReversed = true
    animator.continueAnimation(...*fraction*...)
    

答案 2 :(得分:0)

我尝试了许多解决方案,但是没有人没有为我工作。我写了解决方案,现在一切都很好。我的解决方案:

  1. 拍摄屏幕图像并显示

  2. 完成动画

  3. 为旧状态启动新动画

  4. 暂停动画并设置进度(1-原始进度)

  5. 删除屏幕图像并继续动画

    ?

并且动画曲线选项必须为switch pan.state { ... case .ended, .cancelled, .failed: let velocity = pan.velocity(in: view) let reversed: Bool if abs(velocity.y) < 200 { reversed = progress < 0.5 } else { switch state { case .shown: reversed = velocity.y < 0 case .minimized: reversed = velocity.y > 0 } } if reversed { let overlayView = UIScreen.main.snapshotView(afterScreenUpdates: false) view.addSubview(overlayView) animator?.stopAnimation(false) animator?.finishAnimation(at: .end) startAnimation(state: state.opposite) animator?.pauseAnimation() animator?.fractionComplete = 1 - progress overlayView.removeFromSuperview() animator?.continueAnimation(withTimingParameters: nil, durationFactor: 0.5) } else { animator?.continueAnimation(withTimingParameters: nil, durationFactor: 0) }

linear