Real time blur effect for Navigation Bar
Asked Answered
O

12

37

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

Oxazine answered 5/12, 2014 at 4:35 Comment(4)
From iOS 8.0 there's class added for blur called, "UIVisualEffectView"Competence
Thanks for the response but can you please tell me how to apply this class to navigation bar. Thanks in advanceOxazine
Yes sure, please take reference from few of the answers hereCompetence
but these effects are not all working with Navigation bar. What I want is that as the user scrolls, the content in the background of the Nav bar should give a Blur effect to the front nav bar.Oxazine
W
44

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];
Westering answered 5/12, 2014 at 12:59 Comment(11)
@Shikharvarshney - Yes i'will wait for a minuteWestering
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?Pledgee
@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).Electrodialysis
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 barsCabrilla
@NiranjanRavichandran check the added answer.Undershrub
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.Sandiesandifer
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?Contortion
try this visualEffectView.userInteractionEnabled = falseAtworth
What about Swift 3?Engedus
Blur effect not showing while table view scrolling up. Any issue with table view?Sheridan
@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.Westering
E
19

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()
Elo answered 11/2, 2018 at 1:44 Comment(1)
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() } }Kmeson
M
9

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
Myeshamyhre answered 31/10, 2017 at 7:37 Comment(0)
A
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)

}
Atworth answered 18/7, 2016 at 8:54 Comment(0)
U
3

If, after @Kampai answer you get the status bar not getting in the effect, add this:

bounds.offsetInPlace(dx: 0.0, dy: -20.0)
bounds.size.height = bounds.height + 20.0

Question addressed in this topic.

Undershrub answered 12/10, 2015 at 0:2 Comment(0)
A
3

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
}
Achitophel answered 12/5, 2021 at 10:43 Comment(1)
Also you can check this link with test project github.com/leningradspb/BlurNavigationBarAchitophel
P
2

SWIFT 3:

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)

    }
Premolar answered 1/3, 2017 at 16:8 Comment(2)
When I push a view controller it adds visual effect view above the navigation bar. Any idea why it is happening?Haslett
Just replace one line : bounds = bounds.offsetBy(dx: 0, dy: -20) and all will be workingSpearing
R
0

I first added addBlurEffect() method and then in AppDelegate, I added

 UINavigationBar.appearance().setBackgroundImage(UIImage(), forBarMetrics: .Default)

 UINavigationBar.appearance().shadowImage = UIImage()

 UINavigationBar.appearance().backgroundColor = UIColor.clearColor()

 UINavigationBar.appearance().translucent = true

Now it works for me

Ricciardi answered 2/6, 2016 at 20:15 Comment(0)
C
0

Key note: after u implement above code to add blur view, 1. U need to send your blur view to back to show other things 2. U need to set your blur view user interaction to be false to be able to tap the items on the navigation bar.

Carnegie answered 29/7, 2017 at 18:41 Comment(0)
I
0

iOS NavigationBar Blur Effect

let navigationBar = self.navigationController?.navigationBar
if #available(iOS 13.0, *) {
    navigationBar?.standardAppearance.backgroundColor = .clear
    navigationBar?.standardAppearance.backgroundEffect = UIBlurEffect(style: .systemMaterial)
}
  • Don't forget to align your UITableView to superview(not Safe area)
  • Check that UITableView is on the top in View. In other cases you will see a transparent NavigationBar
Intrastate answered 7/9, 2022 at 14:29 Comment(0)
E
0

I had the same issue, but now I can see that this blur is a default behaviour on iOS 16 at least. My mistake was that I pinned UITableView to the view.safeAreaLayoutGuide.topAnchor. To have a blur effect on navigationBar or tabBar you should just pin to the view edge e.g view.topAnchor

Ellie answered 27/6, 2023 at 9:44 Comment(0)
O
-1

This is neoneye's solution from above, which works perfectly, applied to a UIToolbar.

extension UIToolbar {
    func toolBarBlurEffect() {
        isTranslucent = true
        setBackgroundImage(UIImage(), forToolbarPosition: .any, barMetrics: .default)
        let statusBarHeight: CGFloat = UIApplication.shared.statusBarFrame.height
        var blurFrame = bounds
        blurFrame.size.height += statusBarHeight
        let blurView  = UIVisualEffectView(effect: UIBlurEffect(style: .dark))
        blurView.isUserInteractionEnabled = false
        blurView.frame = blurFrame
        blurView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        addSubview(blurView)
        blurView.layer.zPosition = -1
    }
}

Usage is similar:

navigationController?.toolbar.toolBarBlurEffect()
Outer answered 15/5, 2019 at 3:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.