Animating the fractional part of the UIViewPropertyAnimator to blur the background
So, I am using the new UIViewPropertyAnimator and UIVisualEffectView to achieve the same as Spotlight search when scrolling on the home screen and it blurs the background.
I am using the fractionComplete property to set the procent as blur when panning a UIView.
animator = UIViewPropertyAnimator(duration: 1, curve: .linear) {
self.blurEffectView.effect = nil
}
And the amount of blur changes with a value between 0.0 - 1.0.
animator?.fractionComplete = blurValue
But when I undo the panorama gesture, I want the blur to animate backwards from where there is no blur (e.g. ~ โ 1.0) with a duration of about 0.4 milliseconds.
Right now I just set the fractionComplete to 1.0 when the panorama gesture is canceled. Instead, I want to bring it to life.
I've tried UIView.animate (withDuration .. but it doesn't affect the UIViewPropertyAnimators fractionComplete and that's the only way to blur the UIVisualEffectView.
Any ideas?
source to share
Seems to fractionComplete
have an error (my Stackoverflow question: UIViewPropertyAnimator does not update the view when it waits ), rdar: // 30856746 . The property only sets the state from inactive
to active
, but does not update the view because (I assume) there is some other internal state that does not start.
To fix the problem, you can do this:
animator.startAnimation() // This will change the `state` from inactive to active
animator.pauseAnimation() // This will change `isRunning` back to false, but the `state` will remain as active
// Now any call of `fractionComplete` should update your view correctly!
animator.fractionComplete = /* your value here */
Here's a snippet of the playground:
let liveView = UIView(frame: CGRect(x: 0, y: 0, width: 400, height: 50))
liveView.backgroundColor = .white
PlaygroundPage.current.needsIndefiniteExecution = true
PlaygroundPage.current.liveView = liveView
let square = UIView(frame: CGRect(x: 0, y: 0, width: 50, height: 50))
square.backgroundColor = .red
liveView.addSubview(square)
let animator = UIViewPropertyAnimator.init(duration: 5, curve: .linear)
animator.addAnimations {
square.frame.origin.x = 350
}
let blurView = UIVisualEffectView(effect: UIBlurEffect(style: .dark))
blurView.frame = liveView.bounds
liveView.addSubview(blurView)
animator.addAnimations {
blurView.effect = nil
}
// If you want to restore the blur after it was animated, you have to
// safe a reference to the effect which is manipulated
let effect = blurView.effect
animator.addCompletion {
// In case you want to restore the blur effect
if $0 == .start { blurView.effect = effect }
}
animator.startAnimation()
animator.pauseAnimation()
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
animator.fractionComplete = 0.5
}
DispatchQueue.main.asyncAfter(deadline: .now() + 4) {
// decide the direction you want your animation to go.
// animator.isReversed = true
animator.startAnimation()
}
source to share
If you're still looking for a way to actually animate fractionComplete without using a slider or gesture, I was quite happy with my results using CADisplayLink. You can see my results here: https://gist.github.com/vegather/07993d15c83ffcd5182c8c27f1aa600b
source to share