How do I animate in/out a gaussian blur effect in iOS?

user2005643 picture user2005643 · Feb 26, 2014 · Viewed 13.8k times · Source

For the whole iOS 7 feel, I want to apply a blur effect to a specific portion of the screen to obfuscate it, but I don't want to just throw the blur on instantly, I want to animate it in and animate it out so the user almost sees the blur effect being applied.

Almost as if in Photoshop you changed the gaussian blur value bit by bit from 0 to 10, instead of 0 to 10 in one go.

I've tried a few solutions to this, the most popular suggestion being to simply put the blurred view on top of a non-blurred view, and then lower the alpha value of the blurred view.

This works okay, but not very eye pleasing as there's no transition, it's just an overlay. Example:

enter image description here

What would be a better way to achieve such an effect? I'm familiar with GPUImage, but not sure how to accomplish it with that.

It'd also be great if I could control what percentage of the blur it is at, so it could be applied interactively from the user. (e.g.: user drags halfway, the blur is half applied, etc.)

Answer

Leo Natan picture Leo Natan · Apr 6, 2014

With iOS 9 and above, you can animate the effect on visual effect views:

[UIView animateWithDuration:0.3 animations: ^ {
    visualEffectView.effect = blurEffect;
} completion:nil];

This will achieve the expected effect of animating the blur radius.


I think if you animate a crossfade from non-blurred view -> blurred view, it will be pleasing enough. You need to animate the display of the blur view on top of the non-blurred view.

Let's assume blurView is the view containing the blur effect.

Here are two examples of how to accomplish an animated transition:

[UIView transitionWithView:self.view duration:0.3 options:UIViewAnimationOptionTransitionCrossDissolve animations: ^ {
    [self.view addSubview:blurView];
} completion:nil];

Here I assume blurView has already been set up, and just transition the adding as subview in an animation.

You can also achieve this in a different way:

blurView.alpha = 0.0f;
[UIView animateWithDuration:0.3 animations: ^ {
    blurView.alpha = 1.0f;
} completion:nil];

Here, I make the blur view transparent and animate its appearance. Notice that using this method will not work with hidden, so you want to use the alpha property.


If you wish to control the blur amount interactively, here is an example on how to achieve:

First create an image of the view you want to blur:

UIGraphicsBeginImageContextWithOptions(nonBlurredView.bounds.size, NO, self.view.window.screen.scale);
[nonBlurredView drawViewHierarchyInRect:nonBlurredView.bounds afterScreenUpdates:NO];
UIImage *snapshotImage = UIGraphicsGetImageFromCurrentImageContext();

Keep this image. You only want to redraw in a similar fashion if the view has been changed. Otherwise, you should reuse this image, as it is expensive to draw the hierarchy.

Now, when you need to blur, use the following code:

CIImage *imageToBlur = [CIImage imageWithCGImage:snapshotImage.CGImage];    
CIFilter *gaussianBlurFilter = [CIFilter filterWithName: @"CIGaussianBlur"]; 
[gaussianBlurFilter setValue:imageToBlur forKey: @"inputImage"]; 
[gaussianBlurFilter setValue:@10 forKey: @"inputRadius"]; //Here you input the blur radius - the larger, the 
CIImage *resultImage = [gaussianBlurFilter valueForKey: @"outputImage"]; 
UIImage *endImage = [[UIImage alloc] initWithCIImage:resultImage];

The inputRadius input gives sets up the amount of blur performed. If you animate this, you will achieve an interactive feel.

But I still think the former method is much easier and will feel as good to the user.