在导航栏上方绘制一个视图。

4

我正在开发一个可以从任何其他屏幕唤起的底部菜单。该底部菜单将显示在半透明遮罩层的顶部,我希望该遮罩覆盖全屏幕,包括导航栏和选项卡栏等其他视图。

然而,我无法弄清楚如何使导航栏的内容显示在遮罩层后面。这是我的当前实现的演示。正如您所看到的,即使导航栏的内容在视觉上被显示在遮罩层后面,但仍然可以与其进行交互。

半屏 全屏 返回按钮仍然可以使用
enter image description here enter image description here enter image description here

以下是我当前实现的简化代码:

import SwiftUI

struct MainNavigationView: View {
  var body: some View {
    NavigationView {
      NavigationLink(destination: AnoterView()) {
        Text("Navigate to the next screen")
      }
    }
  }
}

struct AnoterView: View {
  var body: some View {
    ZStack {
      Color(uiColor: .red)
        .edgesIgnoringSafeArea(.all)
        .navigationTitle("Test")
        .navigationBarTitleDisplayMode(.inline)

      ViewWithOverlay()
    }
  }
}

struct ViewWithOverlay: View {
  var body: some View {
    ZStack {

      // I'd like this overlay to be rendered over the navigation bar
      Color(uiColor: .blue)
        .edgesIgnoringSafeArea(.all)

      Color(uiColor: .green)
    }
  }
}

结果如下所示: 在这里输入图片描述

如您所见,尽管蓝色代表我的覆盖层已经画在了红色上方,但标题和返回按钮仍然显示在蓝色的上方。

我知道这是为什么,但我无法想到任何在SwiftUI中可以从任何视图调用的解决方法。

感谢任何帮助。


你要寻找什么输出?你正在ViewWithOverlay中设置标题,这就是为什么它会出现的原因。 - azamsharp
很好的点拨@azamsharp,我已经更新了代码,使得我试图实现的更加明显。在实践中,叠加层只会在底部工作表在屏幕上并默认隐藏时显示。 - Allan Spreys
为什么不使用一个表格?它可以显示在导航栏上方。 - Ptit Xav
很遗憾,这个表格是全屏的,所以我无法使用它来实现我的第一张截图。 - Allan Spreys
@AllanSpreys 你能找到解决办法吗? - Jamil
2个回答

2

你可以做的一件事是将NavigationView放在ZStack中。这样它就会在下面的图层中被上面的图层隐藏。以下是在按钮点击时完全隐藏NavigationBar的代码。

struct ContentView: View {
    
    @State private var isPresented: Bool = false
    
    var body: some View {
        ZStack {
            NavigationView {
                Text("Hello World")
                    .navigationTitle("Welcome")
            }
            
            VStack {
                
            }.frame(maxWidth: isPresented ? .infinity: 0, maxHeight: isPresented ? .infinity: 0)
                .background(.green)
            
            Button("Animate") {
                withAnimation {
                    isPresented.toggle()
                }
            }
        }
    }
}

enter image description here


谢谢@azamsharp。这是一个好答案。覆盖层是半透明的,所以它后面的内容仍然显示。当导航栏一旦出现覆盖层就消失时,看起来有点奇怪。我添加了一些来自我的当前实现的截图。 - Allan Spreys
更新了代码。现在它隐藏了NavigationBar。 - azamsharp
谢谢@azamsharp,我相信这是与Asperi非常相似的答案。当导航视图和其他视图紧挨在一起时,它可以很好地工作。但是当其中一个屏幕非常深入时,实现起来有点困难。 - Allan Spreys
它只需要在ZStack内部正确排序即可。 - azamsharp

0
如果您想覆盖所有内容,那么它应该在根上,包括在NavigationView之上,即:
ZStack {
  NavigationView {
    Color(uiColor: .red).edgesIgnoringSafeArea(.all)
  }

  ViewWithOverlay()  // << here !!
}
.edgesIgnoringSafeArea(.all)

1
谢谢@Asperi,这是一个好答案。然而,问题在于底部表可以从导航视图隐藏得相当远。想象一下一个应用程序,在底部表屏幕之前有7个屏幕。在第一个屏幕中绘制视图以显示第7个屏幕的内容并不是非常有效。我已经更新了我的示例,添加了一个额外的视图,以使这个挑战更加明显。 - Allan Spreys
在SwiftUI概念中,视图的显示/隐藏(实际行为)由某个视图模型管理,因此它与NavigationView或任何其他视图的相对位置无关(也确实不应该与之相关)。因此,我们按照所需的方式构建布局,但是显示条件应该在其他地方(状态对象,环境对象等)设置。例如,请参见https://stackoverflow.com/a/63632033/12299030。 - Asperi
2
是的,您是正确的。但在一个复杂的应用程序示例中,每个屏幕很可能都有自己的视图模型。在我的示例中,MainNavigationView 可能会有 MainNavigationViewModel,而 AnotherView 则可能会有 AnotherViewModel。因此,我希望通过更改 AnotherViewModel 中的更改来影响导航栏的外观,而不会在 AnotherViewModelMainNavigationViewModel 之间创建耦合。 - Allan Spreys

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