iOS 7 style Blur view
Asked Answered
A

6

113

Does anybody know of any controls that will replicate the iOS7 style blur views.

I'm assumming there can be some kind of UIView subclass that will replicate the behavior.

I'm talking about these type views which blur the background extremely thickly so that they have pull effects from the background view.

enter image description here

Advent answered 11/6, 2013 at 4:45 Comment(13)
GPUImage might help.Wen
@Anil well then the question will be when the ios7 SDK is released how can I do this without restricting my app to ios7 only ;).Advent
possible duplicate of iOS7 get wallpaper / cover image and create blurred viewEvery
You can try to use at here this way: StackBluriOSThimblerig
Inspired by the Yahoo Weather iOS App. This project of mine implements the desired iOS 7 effect. github.com/justinmfischer/core-backgroundPavlish
Apple has release a UIImage category that does exactly this. Just trying to find it.Neutralization
The code is linked from WWDC session 201. It's public on github I just can't find it atm.Neutralization
Its session 226 you are looking for and the code can be found by browsing to session 226 at this link and clicking on 'details'. developer.apple.com/wwdc/scheduleCautionary
There are a new good plugins for this : github.com/alexdrone/ios-realtimeblur !enter image description hereRearm
iOS7 style blur effect in Xcode: youtube.com/watch?feature=player_embedded&v=JIdcYbAd-NIAttempt
If you are interested only in blur on iOS7+ but with GPU support and real-time animation, try this: https://mcmap.net/q/125243/-how-can-i-produce-an-effect-similar-to-the-ios-7-blur-viewEnallage
Just use subclass of UINavigationBar instead of UIView... (for iOS7)Rutheruthenia
I've created a thin wrapper around GPUImage that allows for both dynamic and static blurring with variable blur radius and framerate, as well as the ability to add subviews above the blurred area. Check it out if you don't want to dig too deep into GPUImage : MSLiveBlurSimon
E
40

You might be able to modify something like Bin Zhang's RWBlurPopover to do this. That component uses my GPUImage to apply a Gaussian blur to components underneath it, but you could just as easily use a CIGaussianBlur for the same. GPUImage might be a hair faster though.

That component relies on you being able to capture the view behind the one you're presenting, though, and may have trouble with views that animate behind this content. The need to take a trip through Core Graphics to rasterize the background view will slow things down, so we probably don't have sufficiently direct access to be able to do this in a performant manner for overlays on animating views.

As an update to the above, I recently reworked the blurs in GPUImage to support variable radii, allowing for the complete replication of the blur size in iOS 7's control center view. From that, I created the GPUImageiOS7BlurFilter class that encapsulates the proper blur size and color correction that Apple appears to be using here. This is how GPUImage's blur (on the right) compares to the built-in blur (on the left):

Apple's blur GPUImage's blur

I use a 4X downsampling / upsampling to reduce the number of pixels the Gaussian blur has to operate over, so an iPhone 4S can blur the entire screen in roughly 30 ms using this operation.

You still have the challenge of how to pull content into this blur from views behind this one in a performant manner.

Ephesian answered 11/6, 2013 at 16:0 Comment(9)
So how do you think Apple is pulling it off? If you open the Camera app, and pull up Control Center (the settings screen from the bottom), the blur follows what the Camera sees.Wildfowl
@maq - It helps to have under-the-hood access to everything on the system. What someone developing the OS can do is very different from what the public interfaces let us do.Ephesian
So given the public interface, can we make a blur view overlay say something as dynamic as a live camera feed?Wildfowl
@maq - Camera feeds specifically, yes. One way to do this would be to use GPUImage to pull in the camera frames (via AV Foundation) and then have that output both to a GPUImageView for the live camera output and then in parallel be fed into a gaussian blur (and possibly a crop to match the position of the blurred view) and that output to another GPUImageView that would display the blurred content behind your controls. That is possible because we have a fast path from camera frames to OpenGL ES, but we don't have anything similar for generic UI elements.Ephesian
I'm taking a screenshot of a UIView programmatically and using GPUImageGaussianBlurFilter to try to create a similar effect, but the outcome is very different from the Apple style one. The filter seems to be blurring in a grid, with visible squares everywhere, where Apple's is just one smooth sheet.Wildfowl
@maq - Make sure you're using the latest code from the repository, because there was a bug at high blur radii before. That said, the blur only samples a 9-pixel area by default, and so if you increase the multiplier for the blur past that point you'll start to see artifacts from skipping pixels. This is done for performance reasons, but you could modify the vertex and fragment shaders to sample a larger number of pixels. That, or try to apply a CIGaussianBlur, which has a more generalized blur implementation. One of these days, I'll extend this blur to larger radii.Ephesian
I've had some luck using GPUImage's blur like this: resize to 5% > fast blur a few times > resize to 100% > fast blurEmelinaemeline
@Emelinaemeline any difference on the result effect comparing with blur the full image? an how much performance improvement you gain?Unused
@Unused - bendytree's comment no longer applies, because I've restructured the blur filters (as can be seen in the update to the above). There's now a much faster, much better way to do this: #18405407 that uses downsampling and upsampling to speed up the overall blur effect. You'll want to use that specific filter instead.Ephesian
W
28

I am using FXBlurView which works great on iOS5+

https://github.com/nicklockwood/FXBlurView

CocoaPods:

-> FXBlurView (1.3.1)
   UIView subclass that replicates the iOS 7 realtime background blur effect, but works on iOS 5 and above.
   pod 'FXBlurView', '~> 1.3.1'
   - Homepage: http://github.com/nicklockwood/FXBlurView
   - Source:   https://github.com/nicklockwood/FXBlurView.git
   - Versions: 1.3.1, 1.3, 1.2, 1.1, 1.0 [master repo]

I added it by using:

FXBlurView *blurView = [[FXBlurView alloc] initWithFrame:CGRectMake(50, 50, 150, 150)];
[self.blurView setDynamic:YES];
[self.view addSubview:self.blurView];
Windpipe answered 2/9, 2013 at 21:15 Comment(4)
Is there some trick to using FXBlurView? I've tried it, but we have resulted in laggy views on an iPhone 5. Their demo project works fine. Fairly odd.Godship
It depends on what you want to do. When I lay the FXBlurView on top of a UIScrollView I also got a laggy result. I believe this has to do with the way the blur is added. Apple is, if I am not misstaken, directly accessing the GPU when using its own blur, which we cannot do as developers. Hence, @cprcrack solution is actually the best solution here.Windpipe
How have you handled device rotations with FXBlurView? I'm presenting a modal dialog at the moment; the dialog itself rotates fine but the backdrop is squished the wrong way (it needs to be updated after the rotation basically).Gravy
of course, FXBlurView is good option,but when there is matter of CPU usage. than i prefer other blurView. i use this in my UICollectionVIew and UITableView but it increase my CPU usage. in next run i comment those allocations and it becomes normal. i hope, this will help someone.Objurgate
H
28

WARNING: someone in the comments stated that Apple rejects apps using this technique. That did NOT happen to me, but just for your consideration.

This may surprise you, but you can use a UIToolbar, which already includes that standard effect (only iOS 7+). In you view controller's viewDidLoad:

self.view.opaque = NO;
self.view.backgroundColor = [UIColor clearColor]; // Be sure in fact that EVERY background in your view's hierarchy is totally or at least partially transparent for a kind effect!

UIToolbar *fakeToolbar = [[UIToolbar alloc] initWithFrame:self.view.bounds];
fakeToolbar.autoresizingMask = self.view.autoresizingMask;
// fakeToolbar.barTintColor = [UIColor white]; // Customize base color to a non-standard one if you wish
[self.view insertSubview:fakeToolbar atIndex:0]; // Place it below everything
Hellen answered 26/10, 2013 at 15:10 Comment(5)
Yes, it surprised me. I verified, this idea does work. I made just one line change in viewDidLoad like this. - (void)viewDidLoad { [super viewDidLoad]; self.view = [[UIToolbar alloc] initWithFrame:CGRectZero]; } In my case, I layout my views programmatically (old style). I upvote this solution because UIToolbar inherits UIView so fundamentally I don't see any issue in this solution. I will test more as I go along with development & test this solution.Vaginitis
This is a great idea and it appears to work really well. Wish I had more control, but this is as good as it gets! That said, @SudhirJonathan mentioned a link above where the author takes this to the next level - HE STEALS THE CALAYER from a UIToolBar and re-purposes it! Brilliant!Kurtzig
Really? On which grounds? It's not using any private API, and if all innovative ways of doing things would be rejected a lot of effects would not be possible ...Tryma
Worked on my iOS 7.1 iPhoneExciting
Is there a way to "die down" the blurriness?Pneuma
R
13

Since iOS8 you can use UIBlurEffect.

There are a good exemples on iOS8Sampler with UIBlurEffect and UIVibrancyEffect.

Rearm answered 19/9, 2014 at 7:58 Comment(1)
For the lazy: UIVisualEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; UIVisualEffectView *blurView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];Heracles
E
13

The best new Way to get a blured Overlay is to use the new iOS 8 Feature UIVisualEffectView.

UIBlurEffect *effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];

UIVisualEffectView *bluredView = [[UIVisualEffectView alloc] initWithEffect:effect];

bluredView.frame = self.view.bounds;

[self.view addSubview:bluredView];

The UIBlurEffect supports three kinds of Style. Dark, Light and ExtraLight.

Eggplant answered 20/4, 2015 at 8:18 Comment(0)
V
1

You can create a class with a UIToolBar that is a subclass of UIView and instantiate it in a separate view controller. This approach demonstrates a translucent UIToolBar (subclassed by UIView) that provides live feedback (in this case for an AVCaptureSession).

YourUIView.h

#import <UIKit/UIKit.h>

@interface YourUIView : UIView
@property (nonatomic, strong) UIColor *blurTintColor;
@property (nonatomic, strong) UIToolbar *toolbar;
@end

YourUIView.m

#import "YourUIView.h"

@implementation YourUIView

- (instancetype)init
{
    self = [super init];
    if (self) {
        [self setup];
    }
    return self;
}

- (void)setup {
    // If we don't clip to bounds the toolbar draws a thin shadow on top
    [self setClipsToBounds:YES];

    if (![self toolbar]) {
        [self setToolbar:[[UIToolbar alloc] initWithFrame:[self bounds]]];
        [self.toolbar setTranslatesAutoresizingMaskIntoConstraints:NO];
        [self insertSubview:[self toolbar] atIndex:0];

        [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_toolbar]|"
                                                                     options:0
                                                                     metrics:0
                                                                       views:NSDictionaryOfVariableBindings(_toolbar)]];
        [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_toolbar]|"
                                                                     options:0
                                                                     metrics:0
                                                                       views:NSDictionaryOfVariableBindings(_toolbar)]];
    }
}

- (void) setBlurTintColor:(UIColor *)blurTintColor {
    [self.toolbar setBarTintColor:blurTintColor];
}

@end

Once the above UIView has been customized, go ahead and create a class that is a subclass of a ViewController. Below I have created a class that is using an AVCapture session. You must use AVCaptureSession in order to override apple's built in camera configuration. Thus you can overlay the tranclucent UIToolBar from the YourUIView class.

YourViewController.h

#import <UIKit/UIKit.h>

@interface YourViewController : UIViewController
@property (strong, nonatomic) UIView *frameForCapture;
@end

YourViewController.m

#import "YourViewController.h"
#import <AVFoundation/AVFoundation.h>
#import "TestView.h"

@interface YourViewController ()
@property (strong, nonatomic) UIButton *displayToolBar;

@end

@implementation YourViewController


AVCaptureStillImageOutput *stillImageOutput;
AVCaptureSession *session;

- (void) viewWillAppear:(BOOL)animated
{
    session = [[AVCaptureSession alloc] init];
    [session setSessionPreset:AVCaptureSessionPresetPhoto];

    AVCaptureDevice *inputDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    NSError *error;
    AVCaptureDeviceInput *deviceInput = [AVCaptureDeviceInput deviceInputWithDevice:inputDevice error:&error];

    if ([session canAddInput:deviceInput]) {
        [session addInput:deviceInput];
    }

    AVCaptureVideoPreviewLayer *previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:session];
    [previewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
    CALayer *rootLayer = [[self view] layer];
    [rootLayer setMasksToBounds:YES];
    CGRect frame = [[UIScreen mainScreen] bounds];

    self.frameForCapture.frame = frame;

    [previewLayer setFrame:frame];

    [rootLayer insertSublayer:previewLayer atIndex:0];

    stillImageOutput = [[AVCaptureStillImageOutput alloc] init];
    NSDictionary *outputSettings = [[NSDictionary alloc] initWithObjectsAndKeys:AVVideoCodecJPEG, AVVideoCodecKey, nil];
    [stillImageOutput setOutputSettings:outputSettings];

    [session addOutput:stillImageOutput];

    [session startRunning];

    [self.navigationController setNavigationBarHidden:YES animated:animated];
    [super viewWillAppear:animated];
}


- (void)viewDidLoad
{
    [super viewDidLoad];

    /* Open button */

    UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(0, 350, self.view.bounds.size.width, 50)];
    [button addTarget:self action:@selector(showYourUIView:) forControlEvents:UIControlEventTouchUpInside];
    [button setTitle:@"Open" forState:UIControlStateNormal];
    [button setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
    button.backgroundColor = [UIColor greenColor];
    [self.view addSubview:button];

    UIButton *anotherButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 50, self.view.bounds.size.width, 50)];
    [anotherButton addTarget:self action:@selector(showYourUIView:) forControlEvents:UIControlEventTouchUpInside];
    [anotherButton setTitle:@"Open" forState:UIControlStateNormal];
    [anotherButton setTitleColor:[UIColor greenColor] forState:UIControlStateNormal];
    anotherButton.backgroundColor = [UIColor redColor];
    [self.view addSubview:anotherButton];

}

- (void) showYourUIView:(id) sender
{
    TestView *blurView = [TestView new];
    [blurView setFrame:self.view.bounds];
    [self.view addSubview:blurView];
}


@end
Virgulate answered 15/8, 2014 at 21:44 Comment(3)
The answer seems to be completely unrelated to the question.Farceur
@Farceur This is one of the more efficient ways of adding a transparent view to another view controller. I included AVCapture code to show that it could be used for live feedback rather than just adding a blurry background image, as other users have recommended.Virgulate
Ok, apologies, you might want to add something at the beginning that summarizes the approach and the the reasons for using it.Farceur

© 2022 - 2024 — McMap. All rights reserved.