Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to observe changes to fractionComplete in UIViewPropertyAnimator

I've been looking at the very cool new UIViewPropertyAnimator class in iOS 10. It lets you easily do things like pause, resume, and reverse in-flight UIView animations. It used to be that you had to manipulate the underlying CAAnimations the system created in order to do that with UIView animations.

The new UIViewPropertyAnimator class has a property fractionComplete. It varies from 0.0 (beginning of animation) to 1.0 (end of animation.) If you change the value, you can "scrub" an animation from beginning to end.

I have a demo project on Github called KeyframeViewAnimations that lets you use a slider to scrub UIView and CAAnimations back and forth using fairly arcane CAAnimation tricks. As the animation runs, the slider moves from beginning to end to show the progress of the animation. That project was written in Objective-C before Swift was released, but the underlying techniques are the same in Objective-C or Swift.

I decided to create an equivalent project using UIViewPropertyAnimator. There are some quirks, but it's fairly straightforward. One thing I could not figure out how to do cleanly was to observe the progress of the animation's fractionComplete property so that I could update the slider as the animation progresses. I tried setting up KVO (key-value-observing) on the fractionComplete property, but it doesn't trigger a KVO notification until the animation is complete.

What I ended up doing is setting up a timer that runs on a very small interval and queries the UIViewPropertyAnimator's fractionComplete property repeatedly and updating the slider as it progresses. It works, but it's not a very clean way of doing things. It would be much better if there was a way to get notified about the progress of the animation.

I'm hoping there's something I'm missing.

You can see the UIViewPropertyAnimator based project on Github at this link: UIViewPropertyAnimator-test.

The code that gets the progress value from the animator is this code:

func startTimer(_ start: Bool) {   if start {     timer = Timer.scheduledTimer(withTimeInterval: 0.02,      repeats: true) {         timer in         var value = Float(self.viewAnimator.fractionComplete)         if self.animatingBackwards {           value = 1 - value         }         self.animationSlider.value = value      }   }   else {     self.timer?.invalidate()   } } 

I should probably convert the code above to use a CADisplayLink timer instead of a vanilla Timer (NSTimer) but I'm hoping there's a better way.

like image 406
Duncan C Avatar asked Dec 09 '16 03:12

Duncan C


1 Answers

FYI, after researching this, the answer appears to be that no, there is no way to get updates as your animation progresses. You have to set up a timer (Either a Timer or a CADisplayLink and update your progress value each time it fires.

like image 126
Duncan C Avatar answered Sep 30 '22 09:09

Duncan C