10

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

在 iOS10 上一切正常。动画问题发生在 iOS11

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

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

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

此时在 iOS10 上,动画平滑地改变了他的诗句,在 iOS11 上它立即停止并以位帧延迟反转自身。

如果在代码中我检查了.fractionComplete(在我的 UIViewPropertyAnimator 对象上调用它会以百分比值返回动画的完成,从 0.0 开始到 1.0 结束)的值.continueAnimation(...

- 在 iOS 10 上它会保留片刻,例如 if动画仍在继续,只有在一小部分时间跳转到他的互补之后。

- 在 iOS 11 上,它突然跳到他的补充


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

可能是一个错误或者我错过了什么!?


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

正如评论中所链接的,这只发生在非线性曲线上!

4

3 回答 3

7

我也为此奋斗了很长一段时间,但后来我注意到在 iOS 11scrubsLinearly中添加的属性:UIViewPropertyAnimator

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

请注意,此属性的默认值为true,这似乎与使用非线性动画曲线产生冲突。这也可以解释为什么在使用线性定时函数时问题不存在。

设置scrubsLinearlyfalse,动画师似乎按预期工作:

let animator = UIViewPropertyAnimator(duration: 0.25, curve: .easeOut) {
   ...
}
animator.scrubsLinearly = false
于 2017-11-10T12:57:30.037 回答
1
  1. 在 iOS 11 上,将在您反转动画后fractionComplete反转(即) 。1 - originalFractionCompleteanimator.isReversed = true

  2. 持续时间小于 0.1 秒的弹簧动画将立即完成。

所以你可能原本希望反转动画运行整个动画时长的 90%,但是在 iOS 11 上,反转动画实际上运行了 10% 时长,因为isReversed发生了变化,而那 10% 时长小于 0.1s,所以动画会完成立即,看起来没有动画发生。

怎么修?

对于 iOS 10 向后兼容,fractionComplete请在反转动画之前复制该值并将其用于continueAnimation.

例如

let fraction = animator.fractionComplete
animator.isReversed = true
animator.continueAnimation(...*fraction*...)
于 2017-12-21T08:23:23.430 回答
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.

    animator = UIViewPropertyAnimator(duration: 0.3, curve: .linear) {
        startAnimation()
    }
于 2020-07-20T08:26:03.070 回答