导航栏实时模糊效果

37
如何实现类似 iPhone 中的 Trailers 应用程序中导航栏的实时模糊效果。 即当您滚动内容时,导航栏后面的内容应该变得模糊。 请帮我写一些代码。 谢谢! 我想要实现这样的效果:

1
从iOS 8.0开始,新增了一个名为"UIVisualEffectView"的模糊类。 - Hemang
谢谢您的回复,但是您能告诉我如何将这个类应用到导航栏吗?先谢谢了。 - Shikhar varshney
好的,当然可以,请参考这里的一些答案:https://dev59.com/QWAf5IYBdhLWcg3w_W9j。 - Hemang
但是这些效果并不都适用于导航栏。我想要的是,当用户滚动时,导航栏背景中的内容应该给前面的导航栏带来模糊效果。 - Shikhar varshney
12个回答

44

苹果公司在iOS 8.0发布中引入了新的类UIVisualEffectView等,以增加视图的半透明和模糊效果。

以下是如何将其用于导航栏或任何其他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 代码:

- (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.
}

更新:

如果您发现在给navigationBar添加模糊效果后,导航按钮不可见,则需要在添加blurView代码后添加以下代码行。

Swift:

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

Objective C:

[self.navigationController.navigationBar sendSubviewToBack:visualEffectView];

2
我不知道是否有人遇到过这个问题。只做这个会使导航栏变模糊,但我的状态栏仍然是半透明的。有什么办法可以解决吗? - bachman
@NiranjanRavichandran 你试过将边界扩展到屏幕顶部吗?(我没有尝试过,只是想到了这个问题)。 - Nuno Gonçalves
1
在我的情况下,导航栏仍然是白色的...是否需要从界面构建器中更改其他属性?启用半透明会显示与苹果定义的导航栏略有不同的效果。 - frangulyan
4
我的“返回”按钮原来是一个箭头和“返回”字母,但现在只有箭头了,当我按下它时它不会后退。你有什么办法解决这个问题吗? - Alfro
1
尝试一下这个 visualEffectView.userInteractionEnabled = false - Rafat touqir Rafsun
显示剩余6条评论

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
    }
}

使用方法

navigationController?.navigationBar.installBlurEffect()

如果您在detailVC中使用此解决方案,请将此代码附加到该方法的开头for subview in self.subviews { if subview is UIVisualEffectView { subview.removeFromSuperview() } } - Leon Jakonda

9

注意:在iOS 11版本中,函数sendSubviewToBack无法正常工作。为了实现该效果,我们应该使用zPosition将模糊效果视图放置在其他视图下面。

self.visualEffectView.layer.zPosition = -1;

Objective-C 代码

[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代码

  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

4

我已经加入了@Kampai@Damasio的代码,并进行了修改以解决我的问题(与pushNavigation有关)。该代码将支持Swift 4.0+iOS9,Xcode 9

在你的ViewController的ViewDidLoad()中,只需调用

addBlurEffect(toView: self.navigationController?.navigationBar)

功能:

   //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)

}

3

适用于Swift 5,iOS 13+

您可以在AppDelegate文件中使用UINavigationBarAppearance()。别忘了为非滚动模式设置外观。对我而言,结合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
}

此外,您可以通过以下链接检查测试项目:https://github.com/leningradspb/BlurNavigationBar。 - Eduard Kanevsky

3

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)

    }

2
当我推一个视图控制器时,它会在导航栏上方添加一个可视效果视图。有任何想法为什么会发生这种情况? - Karan Bhatia
只需要替换一行代码:bounds = bounds.offsetBy(dx: 0, dy: -20),就可以让所有东西正常工作。 - nerowolfe

0

我首先添加了addBlurEffect()方法,然后在AppDelegate中添加

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

 UINavigationBar.appearance().shadowImage = UIImage()

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

 UINavigationBar.appearance().translucent = true

现在它对我来说可以工作了


0
iOS导航栏模糊效果
let navigationBar = self.navigationController?.navigationBar
if #available(iOS 13.0, *) {
    navigationBar?.standardAppearance.backgroundColor = .clear
    navigationBar?.standardAppearance.backgroundEffect = UIBlurEffect(style: .systemMaterial)
}
  • 别忘了将你的UITableView与父视图对齐(不是安全区域)
  • 检查UITableView是否在视图顶部。否则,你会看到一个透明的导航栏

0
重点提示:在您实现上述代码以添加模糊视图后, 1. 您需要将您的模糊视图发送到后面以显示其他内容 2. 您需要将您的模糊视图用户交互设置为false,以便能够点击导航栏上的项目。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接