Creating a blurring overlay view Creating a blurring overlay view ios ios

Creating a blurring overlay view


You can use UIVisualEffectView to achieve this effect. This is a native API that has been fine-tuned for performance and great battery life, plus it's easy to implement.

Swift:

//only apply the blur if the user hasn't disabled transparency effectsif !UIAccessibility.isReduceTransparencyEnabled {    view.backgroundColor = .clear    let blurEffect = UIBlurEffect(style: .dark)    let blurEffectView = UIVisualEffectView(effect: blurEffect)    //always fill the view    blurEffectView.frame = self.view.bounds    blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]    view.addSubview(blurEffectView) //if you have more UIViews, use an insertSubview API to place it where needed} else {    view.backgroundColor = .black}

Objective-C:

//only apply the blur if the user hasn't disabled transparency effectsif (!UIAccessibilityIsReduceTransparencyEnabled()) {    self.view.backgroundColor = [UIColor clearColor];    UIBlurEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark];    UIVisualEffectView *blurEffectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];    //always fill the view    blurEffectView.frame = self.view.bounds;    blurEffectView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;    [self.view addSubview:blurEffectView]; //if you have more UIViews, use an insertSubview API to place it where needed} else {    self.view.backgroundColor = [UIColor blackColor];}

If you are presenting this view controller modally to blur the underlying content, you'll need to set the modal presentation style to Over Current Context and set the background color to clear to ensure the underlying view controller will remain visible once this is presented overtop.


Core Image

Since that image in the screenshot is static, you could use CIGaussianBlur from Core Image (requires iOS 6). Here is sample: https://github.com/evanwdavis/Fun-with-Masks/blob/master/Fun%20with%20Masks/EWDBlurExampleVC.m

Mind you, this is slower than the other options on this page.

#import <QuartzCore/QuartzCore.h>- (UIImage*) blur:(UIImage*)theImage{       // ***********If you need re-orienting (e.g. trying to blur a photo taken from the device camera front facing camera in portrait mode)    // theImage = [self reOrientIfNeeded:theImage];    // create our blurred image    CIContext *context = [CIContext contextWithOptions:nil];    CIImage *inputImage = [CIImage imageWithCGImage:theImage.CGImage];    // setting up Gaussian Blur (we could use one of many filters offered by Core Image)    CIFilter *filter = [CIFilter filterWithName:@"CIGaussianBlur"];    [filter setValue:inputImage forKey:kCIInputImageKey];    [filter setValue:[NSNumber numberWithFloat:15.0f] forKey:@"inputRadius"];    CIImage *result = [filter valueForKey:kCIOutputImageKey];    // CIGaussianBlur has a tendency to shrink the image a little,     // this ensures it matches up exactly to the bounds of our original image    CGImageRef cgImage = [context createCGImage:result fromRect:[inputImage extent]];    UIImage *returnImage = [UIImage imageWithCGImage:cgImage];//create a UIImage for this function to "return" so that ARC can manage the memory of the blur... ARC can't manage CGImageRefs so we need to release it before this function "returns" and ends.    CGImageRelease(cgImage);//release CGImageRef because ARC doesn't manage this on its own.    return returnImage;    // *************** if you need scaling    // return [[self class] scaleIfNeeded:cgImage];}+(UIImage*) scaleIfNeeded:(CGImageRef)cgimg {    bool isRetina = [[[UIDevice currentDevice] systemVersion] intValue] >= 4 && [[UIScreen mainScreen] scale] == 2.0;    if (isRetina) {        return [UIImage imageWithCGImage:cgimg scale:2.0 orientation:UIImageOrientationUp];    } else {        return [UIImage imageWithCGImage:cgimg];    }}- (UIImage*) reOrientIfNeeded:(UIImage*)theImage{    if (theImage.imageOrientation != UIImageOrientationUp) {        CGAffineTransform reOrient = CGAffineTransformIdentity;        switch (theImage.imageOrientation) {            case UIImageOrientationDown:            case UIImageOrientationDownMirrored:                reOrient = CGAffineTransformTranslate(reOrient, theImage.size.width, theImage.size.height);                reOrient = CGAffineTransformRotate(reOrient, M_PI);                break;            case UIImageOrientationLeft:            case UIImageOrientationLeftMirrored:                reOrient = CGAffineTransformTranslate(reOrient, theImage.size.width, 0);                reOrient = CGAffineTransformRotate(reOrient, M_PI_2);                break;            case UIImageOrientationRight:            case UIImageOrientationRightMirrored:                reOrient = CGAffineTransformTranslate(reOrient, 0, theImage.size.height);                reOrient = CGAffineTransformRotate(reOrient, -M_PI_2);                break;            case UIImageOrientationUp:            case UIImageOrientationUpMirrored:                break;        }        switch (theImage.imageOrientation) {            case UIImageOrientationUpMirrored:            case UIImageOrientationDownMirrored:                reOrient = CGAffineTransformTranslate(reOrient, theImage.size.width, 0);                reOrient = CGAffineTransformScale(reOrient, -1, 1);                break;            case UIImageOrientationLeftMirrored:            case UIImageOrientationRightMirrored:                reOrient = CGAffineTransformTranslate(reOrient, theImage.size.height, 0);                reOrient = CGAffineTransformScale(reOrient, -1, 1);                break;            case UIImageOrientationUp:            case UIImageOrientationDown:            case UIImageOrientationLeft:            case UIImageOrientationRight:                break;        }        CGContextRef myContext = CGBitmapContextCreate(NULL, theImage.size.width, theImage.size.height, CGImageGetBitsPerComponent(theImage.CGImage), 0, CGImageGetColorSpace(theImage.CGImage), CGImageGetBitmapInfo(theImage.CGImage));        CGContextConcatCTM(myContext, reOrient);        switch (theImage.imageOrientation) {            case UIImageOrientationLeft:            case UIImageOrientationLeftMirrored:            case UIImageOrientationRight:            case UIImageOrientationRightMirrored:                CGContextDrawImage(myContext, CGRectMake(0,0,theImage.size.height,theImage.size.width), theImage.CGImage);                break;            default:                CGContextDrawImage(myContext, CGRectMake(0,0,theImage.size.width,theImage.size.height), theImage.CGImage);                break;        }        CGImageRef CGImg = CGBitmapContextCreateImage(myContext);        theImage = [UIImage imageWithCGImage:CGImg];        CGImageRelease(CGImg);        CGContextRelease(myContext);    }    return theImage;}

Stack blur (Box + Gaussian)

  • StackBlur This implements a mix of Box and Gaussian blur. 7x faster than non accelerated gaussian, but not so ugly as box blur. See a demo in here (Java plugin version) or here (JavaScript version). This algorithm is used in KDE and Camera+ and others. It doesn't use the Accelerate Framework but it's fast.

Accelerate Framework

  • In the session “Implementing Engaging UI on iOS” from WWDC 2013 Apple explains how to create a blurred background (at 14:30), and mentions a method applyLightEffect implemented in the sample code using Accelerate.framework.

  • GPUImage uses OpenGL shaders to create dynamic blurs. It has several types of blur: GPUImageBoxBlurFilter, GPUImageFastBlurFilter, GaussianSelectiveBlur, GPUImageGaussianBlurFilter. There is even a GPUImageiOSBlurFilter that “should fully replicate the blur effect provided by iOS 7's control panel” (tweet, article). The article is detailed and informative.

    -(UIImage *)blurryGPUImage:(UIImage *)image withBlurLevel:(NSInteger)blur {        GPUImageFastBlurFilter *blurFilter = [GPUImageFastBlurFilter new];        blurFilter.blurSize = blur;        UIImage *result = [blurFilter imageByFilteringImage:image];        return result;    }

Other stuff

Andy Matuschak said on Twitter: “you know, a lot of the places where it looks like we're doing it in real time, it's static with clever tricks.”

At doubleencore.com they say “we’ve found that a 10 pt blur radius plus a 10 pt increase in saturation best mimics iOS 7’s blur effect under most circumstances”.

A peek at the private headers of Apple's SBFProceduralWallpaperView.

Finally, this isn't a real blur, but remember you can set rasterizationScale to get a pixelated image: http://www.dimzzy.com/blog/2010/11/blur-effect-for-uiview/


I decided to post a written Objective-C version from the accepted answer just to provide more options in this question..

- (UIView *)applyBlurToView:(UIView *)view withEffectStyle:(UIBlurEffectStyle)style andConstraints:(BOOL)addConstraints{  //only apply the blur if the user hasn't disabled transparency effects  if(!UIAccessibilityIsReduceTransparencyEnabled())  {    UIBlurEffect *blurEffect = [UIBlurEffect effectWithStyle:style];    UIVisualEffectView *blurEffectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];    blurEffectView.frame = view.bounds;    [view addSubview:blurEffectView];    if(addConstraints)    {      //add auto layout constraints so that the blur fills the screen upon rotating device      [blurEffectView setTranslatesAutoresizingMaskIntoConstraints:NO];      [view addConstraint:[NSLayoutConstraint constraintWithItem:blurEffectView                                                       attribute:NSLayoutAttributeTop                                                       relatedBy:NSLayoutRelationEqual                                                          toItem:view                                                       attribute:NSLayoutAttributeTop                                                      multiplier:1                                                        constant:0]];      [view addConstraint:[NSLayoutConstraint constraintWithItem:blurEffectView                                                       attribute:NSLayoutAttributeBottom                                                       relatedBy:NSLayoutRelationEqual                                                          toItem:view                                                       attribute:NSLayoutAttributeBottom                                                      multiplier:1                                                        constant:0]];      [view addConstraint:[NSLayoutConstraint constraintWithItem:blurEffectView                                                       attribute:NSLayoutAttributeLeading                                                       relatedBy:NSLayoutRelationEqual                                                          toItem:view                                                       attribute:NSLayoutAttributeLeading                                                      multiplier:1                                                        constant:0]];      [view addConstraint:[NSLayoutConstraint constraintWithItem:blurEffectView                                                       attribute:NSLayoutAttributeTrailing                                                       relatedBy:NSLayoutRelationEqual                                                          toItem:view                                                       attribute:NSLayoutAttributeTrailing                                                      multiplier:1                                                        constant:0]];    }  }  else  {    view.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.7];  }  return view;}

The constraints could be removed if you want incase if you only support portrait mode or I just add a flag to this function to use them or not..