Real time blur effect for Navigation Bar

27,728

Solution 1

Apple has introduced new classes UIVisualEffectView and more to add translucency and blur effect on views from iOS 8.0 release.

Here how you can use it to add a blur effect to navigation bar or any other UIView:

Swift 5

func addBlurEffect() {
    let bounds = self.navigationController?.navigationBar.bounds
    let visualEffectView = UIVisualEffectView(effect: UIBlurEffect(style: .light))
    visualEffectView.frame = bounds ?? CGRect.zero
    visualEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
    self.navigationController?.navigationBar.addSubview(visualEffectView)        

    // Here you can add visual effects to any UIView control.
    // Replace custom view with navigation bar in the above code to add effects to the custom view.
}

Objective C Code:

- (void) addBlurEffect {
    // Add blur view
    CGRect bounds = self.navigationController.navigationBar.bounds;
    UIVisualEffectView *visualEffectView = [[UIVisualEffectView alloc] initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]];
    visualEffectView.frame = bounds;
    visualEffectView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
    [self.navigationController.navigationBar addSubview:visualEffectView];
    self.navigationController.navigationBar.backgroundColor = [UIColor clearColor];
    [self.navigationController.navigationBar sendSubviewToBack:visualEffectView];

    // Here you can add visual effects to any UIView control.
    // Replace custom view with navigation bar in the above code to add effects to the custom view.
}

UPDATE:

If you find that after adding blur effect on navigationBar, navigation buttons are not visible then add below line after adding blurView code.

Swift:

self.navigationController?.navigationBar.sendSubview(toBack: visualEffectView)

Objective C:

[self.navigationController.navigationBar sendSubviewToBack:visualEffectView];

Solution 2

Swift 4

extension UINavigationBar {
    func installBlurEffect() {
        isTranslucent = true
        setBackgroundImage(UIImage(), for: .default)
        let statusBarHeight: CGFloat = UIApplication.shared.statusBarFrame.height
        var blurFrame = bounds
        blurFrame.size.height += statusBarHeight
        blurFrame.origin.y -= statusBarHeight
        let blurView  = UIVisualEffectView(effect: UIBlurEffect(style: .light))
        blurView.isUserInteractionEnabled = false
        blurView.frame = blurFrame
        blurView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        addSubview(blurView)
        blurView.layer.zPosition = -1
    }
}

Usage

navigationController?.navigationBar.installBlurEffect()

Solution 3

Noted: on iOS 11, function sendSubviewToBack does not work normally. In order to achieve that, we should use zPosition to place the blur effect view under other views.

self.visualEffectView.layer.zPosition = -1;

Objective-C code

[self.navigationController.navigationBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
    self.navigationController.navigationBar.shadowImage = [UIImage new];
    self.navigationController.navigationBar.barTintColor = [UIColor whiteColor];
    self.navigationController.navigationBar.backgroundColor = [UIColor clearColor];
    self.navigationController.navigationBar.translucent = YES;
    // Add blur view
    CGRect bounds = self.navigationController.navigationBar.bounds;
    bounds.size.height += 20;
    bounds.origin.y -= 20;
    _visualEffectView = [[UIVisualEffectView alloc] initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]];
    self.visualEffectView.frame = bounds;
    self.visualEffectView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
    self.visualEffectView.userInteractionEnabled = NO;
    self.visualEffectView.layer.zPosition = -1;
    [self.navigationController.navigationBar addSubview:self.visualEffectView];
    [self.navigationController.navigationBar sendSubviewToBack:self.visualEffectView];

Swift 4 code

  self.navigationController?.navigationBar.isTranslucent = true
    self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
    let visualEffectView   = UIVisualEffectView(effect: UIBlurEffect(style: .light))
    var bounds = view.bounds
    bounds.size.height += 20
    bounds.origin.y -= 20
    visualEffectView.isUserInteractionEnabled = false
    visualEffectView.frame = bounds
    visualEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
    self.navigationController?.navigationBar.addSubview(visualEffectView)
    visualEffectView.layer.zPosition = -1

Solution 4

I've added @Kampai's,@Damasio's with my tweaks to resolve my issues(which was pushNavigation related).Code will support Swift 4.0+, iOS9, Xcode 9

In your ViewController's ViewDidLoad(), just call

addBlurEffect(toView: self.navigationController?.navigationBar)

function:

   //MARK :- It can be used in navBarGlassEffect view
func addBlurEffect(toView view:UIView?) {
    // Add blur view
    guard let view = view else { return }


    //This will let visualEffectView to work perfectly
    if let navBar = view as? UINavigationBar{
        navBar.setBackgroundImage(UIImage(), for: .default)
        navBar.shadowImage = UIImage()
    }


    var bounds = view.bounds
    bounds.offsetBy(dx: 0.0, dy: -20.0)
    bounds.size.height = bounds.height + 20.0


    let blurEffect = UIBlurEffect(style: .dark)
    let visualEffectView = UIVisualEffectView(effect: blurEffect)

    visualEffectView.isUserInteractionEnabled = false
    visualEffectView.frame = bounds
    visualEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
    view.insertSubview(visualEffectView, at: 0)

}

Solution 5

Swift 5, iOS 13 +

You can use UINavigationBarAppearance() in AppDelegate file. And don't forget set appearance for not scrolling mode. For me it works perfect with navigationBar.prefersLargeTitles.

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    let appearance = UINavigationBarAppearance()
    appearance.configureWithTransparentBackground()
    appearance.backgroundColor = UIColor.clear
    appearance.backgroundEffect = UIBlurEffect(style: .light) // or dark
    
    let scrollingAppearance = UINavigationBarAppearance()
    scrollingAppearance.configureWithTransparentBackground()
    scrollingAppearance.backgroundColor = .white // your view (superview) color
    
    UINavigationBar.appearance().standardAppearance = appearance
    UINavigationBar.appearance().scrollEdgeAppearance = scrollingAppearance
    UINavigationBar.appearance().compactAppearance = scrollingAppearance
    
    return true
}
Share:
27,728
Shikhar varshney
Author by

Shikhar varshney

Updated on May 13, 2021

Comments

  • Shikhar varshney
    Shikhar varshney almost 3 years

    How to achieve the real time blurring effect for the navigation bar just like the Trailers app in iPhone.

    i.e As you scroll the contents should get blurred behind the navigation bar. Please help me with some code.

    Thanks!

    I want to achieve an effect like this:-

    enter image description here

  • Kampai
    Kampai over 9 years
    @Shikharvarshney - Yes i'will wait for a minute
  • bachman
    bachman almost 9 years
    I don't know if anyone has faced this problem. Doing this only blurs the nav bar but my status bar still appears translucent. Any way to fix that?
  • Nuno Gonçalves
    Nuno Gonçalves over 8 years
    @NiranjanRavichandran did you try to make the bounds go further to the top of the screen (I didn't try it just came to my mind).
  • frangulyan
    frangulyan over 8 years
    in my case the bar is still white... any other properties need to be changed from interface builder? enabling translucent shows a bit different effect, the one defined by apple for bars
  • Damasio
    Damasio over 8 years
    @NiranjanRavichandran check the added answer.
  • malhal
    malhal over 8 years
    It works but its not identical to the built in blurring of nav bars and tool bars. Edit changed to ExtraLight and it now matches.
  • Alfro
    Alfro almost 8 years
    My back button was an arrow and "back" letters, but now there is only the arrow and when I press it it won't go back. Any idea how to fix this?
  • Rafat touqir Rafsun
    Rafat touqir Rafsun almost 8 years
    try this visualEffectView.userInteractionEnabled = false
  • Tarvo Mäesepp
    Tarvo Mäesepp over 7 years
    What about Swift 3?
  • Karan Bhatia
    Karan Bhatia about 7 years
    When I push a view controller it adds visual effect view above the navigation bar. Any idea why it is happening?
  • nerowolfe
    nerowolfe over 6 years
    Just replace one line : bounds = bounds.offsetBy(dx: 0, dy: -20) and all will be working
  • Rajesh Maurya
    Rajesh Maurya over 5 years
    Blur effect not showing while table view scrolling up. Any issue with table view?
  • Kampai
    Kampai over 5 years
    @Rajesh: Please create a new question and add screenshots and details in that, with code. Paste a link of that question here, so that I can help you.
  • Eduard Kanevsky
    Eduard Kanevsky almost 3 years
    Also you can check this link with test project github.com/leningradspb/BlurNavigationBar
  • Leon Jakonda
    Leon Jakonda about 2 years
    if you use that solution in detailVC, append this code to the beginning the method for subview in self.subviews { if subview is UIVisualEffectView { subview.removeFromSuperview() } }