UIViewPropertyAnimator different behaviour on iOS10 and iOS11 reversing an animation. Bug on `isReversed` and `fractionComplete` properties?
Asked Answered
A

3

10

THE PROBLEM
Running the same code on iOS10 and iOS11 my UIViewPropertyAnimator has a different behaviour just after changing of his .isReversed property.

Everything is ok on iOS10. The animation problem happens on iOS11

CONDITIONS
It's true for any animations, not only for a particular one, and it is verifiable both by watching the animation and within the code. It happens both on simulators and real devices.

DETAILS
Once created a UIViewPropertyAnimator with his animation, during its running I just call .pauseAnimation() and change the .isReversed property to true. After that I resume the animation calling:

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

at this point on iOS10 the animation smoothly changes his verse, on iOS11 it stops immediately and reverses itself with a bit frames lag.

If in code I check the value of .fractionComplete (called on my UIViewPropertyAnimator object it gives me back the completion of the animation in his percent value, starting from 0.0 and ending at 1.0) just after .continueAnimation(...

- On iOS 10 it remains for a few moments like if the animation is continuing and only after some fractions of time jumps to his complementary.

- On iOS 11 it jumps suddenly on his complementary


On the documentation there are non updates related to this, just a couple of new properties for the UIViewPropertyAnimator but not used because I'm targeting iOS10

Could be a bug or I'm missing something!?


Little update: just tested, same behaviour on iOS 11.0.1 and on iOS 11.1 beta1

As linked in the comment, this happens only with a non-linear curve!

Alphard answered 25/9, 2017 at 13:39 Comment(4)
Someone seems to have similar problems: rdar://problem/34674968 linkAlphard
Try setting new timing parameters instead of passing nil: let paras = UISpringTimingParameters(dampingRatio: 0.8, initialVelocity: CGVector(dx: 0, dy: 100)) and animator.continueAnimation(withTimingParameters: paras, durationFactor: 1)Nonsectarian
In my case I would use continueAnimation(withTimingParameters: UICubicTimingParameters(animationCurve: UIViewAnimationCurve.easeIn) ...) but it has the described problem. As you can find inside the link on my previous comment the problems is present performing animations with a non-linear curve! Indeed if I use continueAnimation(withTimingParameters: UICubicTimingParameters(animationCurve: UIViewAnimationCurve.linear) ...), using a linear curve, it hasn't any problem! But I will try with your trimmingParamenters!Alphard
In my case I had the "jumping" only when the configured property animator had a non-linear curve and then passing nil for withTimingParameters.Nonsectarian
I
7

I have been fighting this for quite a while as well, but then I noticed the scrubsLinearly property that was added to UIViewPropertyAnimator in iOS 11:

Defaults to true. Provides the ability for an animator to pause and scrub either linearly or using the animator’s current timing.

Note that the default of this property is true, which seems to cause a conflict with using a non-linear animation curve. That might also explain why the issue is not present when using a linear timing function.

Setting scrubsLinearly to false, the animator seems to work as expected:

let animator = UIViewPropertyAnimator(duration: 0.25, curve: .easeOut) {
   ...
}
animator.scrubsLinearly = false
Incompliant answered 10/11, 2017 at 12:57 Comment(1)
You'r a Genius! Thank you ^.^Alphard
T
1
  1. On iOS 11, fractionComplete will be reversed (that is, 1 - originalFractionComplete) after you reverse animation by animator.isReversed = true.

  2. Spring animation that have less than 0.1s duration will complete instantly.

So you may originally want the reversed animation runs 90% of the entire animation duration, but on iOS 11, the reversed animation actually runs 10% duration because isReversed changed, and that 10% duration is less than 0.1s, so the animation will be completed instantly and looks like no animation happened.

How to fix?

For iOS 10 backward compatibility, copy the fractionComplete value before you reverse animation and use it for continueAnimation.

e.g.

let fraction = animator.fractionComplete
animator.isReversed = true
animator.continueAnimation(...*fraction*...)
Tar answered 21/12, 2017 at 8:23 Comment(0)
R
0

I have tried many solutions, but no one didn't work for me. I wrote my solution and everything is fine now. My solution:

  1. take an image of the screen and show it

  2. finish animation

  3. start new animation for old state

  4. pause the animation and set progress (1 - original progress)

  5. remove screen image and continue animation

    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)
        }
    

And the animation curve option must be linear.

    animator = UIViewPropertyAnimator(duration: 0.3, curve: .linear) {
        startAnimation()
    }
Roach answered 20/7, 2020 at 8:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.