UIViewPropertyAnimator 在 iOS10 和 iOS11 反转动画时的不同行为。关于 isReversed 和 fractionComplete 属性的错误?
UIViewPropertyAnimator different behaviour on iOS10 and iOS11 reversing an animation. Bug on `isReversed` and `fractionComplete` properties?
问题
运行 iOS10 和 iOS11 上的相同代码 我的 UIViewPropertyAnimator 在更改 .isReversed
属性.
[=39 后具有不同的行为=]
iOS10 一切正常。动画问题发生在 iOS11
条件
对于任何动画都是如此,而不仅仅是特定的动画,并且可以通过观看动画和代码来验证。
它在模拟器和真实设备上都会发生。
详情
一旦用他的动画创建了一个 UIViewPropertyAnimator,在它的 运行 期间我只是调用 .pauseAnimation()
并将 .isReversed
属性 更改为 true。之后我继续调用动画:
continueAnimation(withTimingParameters parameters: UITimingCurveProvider?, durationFactor: CGFloat)
在 iOS10 的这一点上,动画平滑地改变了他的诗句,在 iOS11 上,它立即停止并自行反转,但有一点帧延迟。
如果在代码中检查 .fractionComplete
的值(在我的 UIViewPropertyAnimator 对象上调用,它会返回动画完成的百分比值,从 0.0 开始到 1.0 结束)
.continueAnimation(...
之后
- 在 iOS 10 上,它会保留片刻,就像动画在继续一样,只有在几分之一的时间后才会跳到他的补充。
- 在 iOS 11 上它突然跳到他的互补
在文档中没有与此相关的更新,只有 UIViewPropertyAnimator 的几个新属性但未使用,因为我的目标是 iOS10
可能是错误或我遗漏了什么!?
小更新:刚刚测试,iOS 11.0.1 和 iOS 11.1 beta1
上的行为相同
如评论中所链接,这仅发生在非线性曲线上!
我也为此苦苦挣扎了一段时间,但后来我注意到 scrubsLinearly
属性 在 iOS 11 中被添加到 UIViewPropertyAnimator
中:
Defaults to true. Provides the ability for an animator to pause and scrub either linearly or using the animator’s current timing.
注意这个属性的默认是true
,好像和使用非线性动画曲线有冲突。这也可以解释为什么在使用线性计时函数时问题不存在。
将 scrubsLinearly
设置为 false
,动画师似乎按预期工作:
let animator = UIViewPropertyAnimator(duration: 0.25, curve: .easeOut) {
...
}
animator.scrubsLinearly = false
在iOS 11,fractionComplete
将在你通过animator.isReversed = true
反转动画后反转(即1 - originalFractionComplete
)。
Spring 持续时间小于 0.1 秒的动画将立即完成。
所以您最初可能希望反向动画运行整个动画持续时间的 90%,但是在 iOS 11 上,反向动画实际上运行了 10% 的持续时间,因为 isReversed
发生了变化,而 10 % 持续时间小于 0.1s,所以动画会立即完成,看起来没有任何动画发生。
如何修复?
为了 iOS 10 向后兼容,在反转动画之前复制 fractionComplete
值并将其用于 continueAnimation
。
例如
let fraction = animator.fractionComplete
animator.isReversed = true
animator.continueAnimation(...*fraction*...)
我尝试了很多解决方案,但没有一个不适合我。我写了我的解决方案,现在一切都很好。我的解决方案:
拍摄屏幕图像并显示
完成动画
为旧状态启动新动画
暂停动画并设置进度(1 - 原始进度)
删除屏幕图像并继续动画
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
。
animator = UIViewPropertyAnimator(duration: 0.3, curve: .linear) {
startAnimation()
}
问题
运行 iOS10 和 iOS11 上的相同代码 我的 UIViewPropertyAnimator 在更改 .isReversed
属性.
[=39 后具有不同的行为=]
iOS10 一切正常。动画问题发生在 iOS11
条件
对于任何动画都是如此,而不仅仅是特定的动画,并且可以通过观看动画和代码来验证。
它在模拟器和真实设备上都会发生。
详情
一旦用他的动画创建了一个 UIViewPropertyAnimator,在它的 运行 期间我只是调用 .pauseAnimation()
并将 .isReversed
属性 更改为 true。之后我继续调用动画:
continueAnimation(withTimingParameters parameters: UITimingCurveProvider?, durationFactor: CGFloat)
在 iOS10 的这一点上,动画平滑地改变了他的诗句,在 iOS11 上,它立即停止并自行反转,但有一点帧延迟。
如果在代码中检查 .fractionComplete
的值(在我的 UIViewPropertyAnimator 对象上调用,它会返回动画完成的百分比值,从 0.0 开始到 1.0 结束)
.continueAnimation(...
之后
- 在 iOS 10 上,它会保留片刻,就像动画在继续一样,只有在几分之一的时间后才会跳到他的补充。
- 在 iOS 11 上它突然跳到他的互补
在文档中没有与此相关的更新,只有 UIViewPropertyAnimator 的几个新属性但未使用,因为我的目标是 iOS10
可能是错误或我遗漏了什么!?
小更新:刚刚测试,iOS 11.0.1 和 iOS 11.1 beta1
上的行为相同如评论中所链接,这仅发生在非线性曲线上!
我也为此苦苦挣扎了一段时间,但后来我注意到 scrubsLinearly
属性 在 iOS 11 中被添加到 UIViewPropertyAnimator
中:
Defaults to true. Provides the ability for an animator to pause and scrub either linearly or using the animator’s current timing.
注意这个属性的默认是true
,好像和使用非线性动画曲线有冲突。这也可以解释为什么在使用线性计时函数时问题不存在。
将 scrubsLinearly
设置为 false
,动画师似乎按预期工作:
let animator = UIViewPropertyAnimator(duration: 0.25, curve: .easeOut) {
...
}
animator.scrubsLinearly = false
在iOS 11,
fractionComplete
将在你通过animator.isReversed = true
反转动画后反转(即1 - originalFractionComplete
)。Spring 持续时间小于 0.1 秒的动画将立即完成。
所以您最初可能希望反向动画运行整个动画持续时间的 90%,但是在 iOS 11 上,反向动画实际上运行了 10% 的持续时间,因为 isReversed
发生了变化,而 10 % 持续时间小于 0.1s,所以动画会立即完成,看起来没有任何动画发生。
如何修复?
为了 iOS 10 向后兼容,在反转动画之前复制 fractionComplete
值并将其用于 continueAnimation
。
例如
let fraction = animator.fractionComplete
animator.isReversed = true
animator.continueAnimation(...*fraction*...)
我尝试了很多解决方案,但没有一个不适合我。我写了我的解决方案,现在一切都很好。我的解决方案:
拍摄屏幕图像并显示
完成动画
为旧状态启动新动画
暂停动画并设置进度(1 - 原始进度)
删除屏幕图像并继续动画
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
。
animator = UIViewPropertyAnimator(duration: 0.3, curve: .linear) {
startAnimation()
}