Skip to content

Instantly share code, notes, and snippets.

@vegather
Last active February 26, 2024 16:06
Show Gist options
  • Save vegather/07993d15c83ffcd5182c8c27f1aa600b to your computer and use it in GitHub Desktop.
Save vegather/07993d15c83ffcd5182c8c27f1aa600b to your computer and use it in GitHub Desktop.
A simple view to animate in and out a blurry overlay. Use .blurIn() and .blurOut() to animate the blur. User interaction is passed through when the view is not blurry. NOTE: If you use storyboards, you need to drag out a UIVisualEffectView and set the class. It doesn't work if you drag out a plain old UIView.
class BlurryOverlayView: UIVisualEffectView {
private var animator: UIViewPropertyAnimator!
private var delta: CGFloat = 0 // The amount to change fractionComplete for each tick
private var target: CGFloat = 0 // The fractionComplete we're animating to
private(set) var isBlurred = false
private var displayLink: CADisplayLink!
override init(effect: UIVisualEffect?) {
super.init(effect: effect)
setup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
}
// Common init
private func setup() {
effect = nil // Starts out with no blur
isHidden = true // Enables user interaction through the view
// The animation to add an effect
animator = UIViewPropertyAnimator(duration: 1, curve: .easeInOut) {
self.effect = UIBlurEffect(style: .light)
}
animator.pausesOnCompletion = true // Fixes background bug
// Using a display link to animate animator.fractionComplete
displayLink = CADisplayLink(target: self, selector: #selector(tick))
displayLink.isPaused = true
displayLink.add(to: .main, forMode: .commonModes)
}
func blurIn(amount: CGFloat = 0.2, duration: TimeInterval = 0.3) {
guard isBlurred == false else { return }
isHidden = false // Disable user interaction
target = amount
delta = amount / (60 * CGFloat(duration)) // Assuming 60hz refresh rate
// Start animating fractionComplete
displayLink.isPaused = false
}
func blurOut(duration: TimeInterval = 0.3) {
guard isBlurred else { return }
target = 0
delta = -1 * animator.fractionComplete / (60 * CGFloat(duration)) // Assuming 60hz refresh rate
// Start animating fractionComplete
displayLink.isPaused = false
}
@objc private func tick() {
animator.fractionComplete += delta
if isBlurred && animator.fractionComplete <= 0 {
// Done blurring out
isBlurred = false
isHidden = true
displayLink.isPaused = true
} else if isBlurred == false && animator.fractionComplete >= target {
// Done blurring in
isBlurred = true
displayLink.isPaused = true
}
}
}
@minguking
Copy link

Legend

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment