Animate the fractionComplete of UIViewPropertyAnimator for blurring the background

It seems that fractionComplete has a bug (my question on Stackoverflow: UIViewPropertyAnimator does not update the view when expected), rdar://30856746. The property only sets the state from inactive to active, but does not update the view, because (I assume) there is another internal state that does not trigger.

To workaround 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 is a playground snippet to play around:

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

If you're still looking for a way to actually animate fractionComplete without the use of a slider or a gesture, I was quite happy with my results using a CADisplayLink. You can see my results here: https://gist.github.com/vegather/07993d15c83ffcd5182c8c27f1aa600b