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

Kampai
  • 22,848
  • 21
  • 95
  • 95
Shikhar varshney
  • 816
  • 1
  • 9
  • 23
  • 1
    From iOS 8.0 there's class added for blur called, ["`UIVisualEffectView`"](https://developer.apple.com/Library/ios/documentation/UIKit/Reference/UIVisualEffectView/index.html) – Hemang Dec 05 '14 at 04:38
  • Thanks for the response but can you please tell me how to apply this class to navigation bar. Thanks in advance – Shikhar varshney Dec 05 '14 at 05:04
  • Yes sure, please take reference from few of the answers [here](http://stackoverflow.com/questions/24067719/how-to-use-uivisualeffectview) – Hemang Dec 05 '14 at 05:07
  • 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. – Shikhar varshney Dec 05 '14 at 05:44

12 Answers12

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];
Kampai
  • 22,848
  • 21
  • 95
  • 95
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()
neoneye
  • 50,398
  • 25
  • 166
  • 151
  • 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() } }` – Leon Jakonda Mar 02 '22 at 16:32
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
Martin Le
  • 719
  • 7
  • 14
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)

}
Rafat touqir Rafsun
  • 2,777
  • 28
  • 24
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.

Community
  • 1
  • 1
Damasio
  • 496
  • 5
  • 14
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
}
Eduard Kanevsky
  • 140
  • 2
  • 6
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)

    }
Yaroslav Dukal
  • 3,894
  • 29
  • 36
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

alitosuner
  • 984
  • 1
  • 10
  • 15
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.

Developer Sheldon
  • 2,140
  • 1
  • 11
  • 17
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
yoAlex5
  • 29,217
  • 8
  • 193
  • 205
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

-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()
Gibson
  • 1
  • 1