如何在SwiftUI NavigiationView中删除默认导航栏空间

Vap*_*ant 13 ios swift swiftui swiftui-list swiftui-bug

我是SwiftUI的新手(就像大多数人一样),试图弄清楚如何删除我在NavigationView中嵌入的List上方的空白。

在此图像中,您可以看到列表上方有一些空白

当前版本

我要完成的是

理想版本

我试过使用

.navigationBarHidden(true)
Run Code Online (Sandbox Code Playgroud)

但这并没有进行任何明显的更改。

我目前正在这样设置我的navigationView

 NavigationView {
                FileBrowserView(jsonFromCall: URLRetrieve(URLtoFetch: applicationDelegate.apiURL))
                    .navigationBarHidden(true)
                }
Run Code Online (Sandbox Code Playgroud)

其中FileBrowserView是具有列表和像这样定义的单元格的视图

List {
   Section(header: Text("Root")){
    FileCell(name: "Test", fileType: "JPG",fileDesc: "Test number 1")

                    FileCell(name: "Test 2", fileType: "txt",fileDesc: "Test number 2")
                    FileCell(name: "test3", fileType: "fasta", fileDesc: "")
}
}
Run Code Online (Sandbox Code Playgroud)

我确实要注意,这里的最终目标是您将能够单击这些单元格来更深地浏览到文件树,因此在更深层的导航上应该在栏上显示“后退”按钮,但是我不需要在我的初始视图中排名最高。

gra*_*ell 35

由于某些原因,SwiftUI要求您还设置.navigationBarTitle为.navigationBarHidden可以正常工作。

NavigationView {
    FileBrowserView(jsonFromCall: URLRetrieve(URLtoFetch: applicationDelegate.apiURL))
        .navigationBarTitle("")
        .navigationBarHidden(true)
}
Run Code Online (Sandbox Code Playgroud)

更新资料

正如@Peacemoon在注释中指出的那样,无论您是否在后续视图中进行设置navigationBarHidden,当您在导航堆栈中进行更深入的浏览时,导航栏将保持隐藏false。就像我在评论中说的那样,这可能是由于Apple实施不佳或仅是糟糕的文档(谁知道,也许有一种“正确”的方式来实现)的结果。

无论如何,我想出了一种解决方法,似乎可以产生原始海报的预期效果。我很犹豫地推荐它,因为它看上去似乎不必要,但如果没有任何隐藏和取消隐藏导航栏的简单方法,这就是我能做的最好的事情。

本示例使用三个视图- View1具有隐藏的导航栏,View2并且View3两个视图均带有可见的带有标题的导航栏。

struct View1: View {
    @State var isNavigationBarHidden: Bool = true

    var body: some View {
        NavigationView {
            ZStack {
                Color.red
                NavigationLink("View 2", destination: View2(isNavigationBarHidden: self.$isNavigationBarHidden))
            }
            .navigationBarTitle("Hidden Title")
            .navigationBarHidden(self.isNavigationBarHidden)
            .onAppear {
                self.isNavigationBarHidden = true
            }
        }
    }
}

struct View2: View {
    @Binding var isNavigationBarHidden: Bool

    var body: some View {
        ZStack {
            Color.green
            NavigationLink("View 3", destination: View3())
        }
        .navigationBarTitle("Visible Title 1")
        .onAppear {
            self.isNavigationBarHidden = false
        }
    }
}

struct View3: View {
    var body: some View {
        Color.blue
            .navigationBarTitle("Visible Title 2")
    }
}
Run Code Online (Sandbox Code Playgroud)

设置navigationBarHidden到false导航堆栈上的更深层次的看法似乎并不恰当覆盖最初设置视图的偏好navigationBarHidden来true,所以唯一的解决方法我能想出是使用绑定改变原来的观点的偏好时,一个新的视图被推到导航堆栈上。

就像我说的那样,这是一个棘手的解决方案,但是如果没有Apple的官方解决方案,这就是我能想到的最好的解决方案。

  • 这解决了我的问题!这是很奇怪的,您必须具有标题才能隐藏导航栏。 (3认同)
  • @SambitPrakash 我以前从未真正将 TabView 嵌套在 NavigationView 中,据我所知,Apple 似乎没有在他们的应用程序中以这种方式嵌套它们。我从来没有完全清楚是否打算将 TabView 嵌套在 NavigationView 中,而且我知道 SwiftUI 有一些奇怪的错误,当您以这种方式嵌套它们时,就会弹出这些错误。对我来说,TabView 一直感觉是比 NavigationView 更高级别的导航形式。如果您将 NavigationView 嵌套在 TabView 中,我相信我的解决方法应该仍然有效。 (3认同)
  • 该错误仍然存​​在于beta之外:/ (2认同)
  • @Peacemoon 我之前没有注意到这一点。总而言之,感觉苹果的实施相当草率。您不必只是为了隐藏导航栏而设置标题,并且在下一个视图上将“navigationBarHidden”设置为“false”应该会取消隐藏导航栏,但事实并非如此。我最终厌倦了 SwiftUI 的文档记录有多么糟糕,并回到了 UIKit,事实上,至少有 20 个人来到这里只是为了学习如何隐藏导航栏,这对 Apple 的实现和/或文档来说非常糟糕。抱歉我没有更好的答案给你。 (2认同)
  • @kar 令人失望的是,这个答案仍然受到关注和投票。我编写它是为了解决应该是临时错误的问题。我最近没有测试过它,但显然它有很多问题。有些人还问是否可以在不使用 NavigationView 的情况下在视图之间导航。答案是肯定的,但您实际上必须从头开始编写自己的 NavigationView。您不能只是神奇地在视图之间导航。必须有一些东西来管理这些视图并提供它们之间的转换,这就是我们拥有 NavigationView 的原因。 (2认同)
  • 这是我发现的实现此功能的唯一方法,令人遗憾的是我们必须诉诸这种黑客技术来实现如此简单的事情。感谢@graycampbell 解决了这个问题。 (2认同)

The*_*ow_ 25

a 的目的NavigationView是在视图顶部添加导航栏。在 iOS 中,有两种导航栏:大导航栏和标准导航栏。

在此处输入图片说明

如果你不想要导航栏:

FileBrowserView(jsonFromCall: URLRetrieve(URLtoFetch: applicationDelegate.apiURL))
Run Code Online (Sandbox Code Playgroud)

如果你想要一个大的导航栏(通常用于你的顶级视图):

NavigationView {
    FileBrowserView(jsonFromCall: URLRetrieve(URLtoFetch: applicationDelegate.apiURL))
    .navigationBarTitle(Text("Title"))
}
Run Code Online (Sandbox Code Playgroud)

如果您想要标准(内联)导航栏(通常用于子级视图):

NavigationView {
    FileBrowserView(jsonFromCall: URLRetrieve(URLtoFetch: applicationDelegate.apiURL))
    .navigationBarTitle(Text("Title"), displayMode: .inline)
}
Run Code Online (Sandbox Code Playgroud)

希望这个回答能帮到你。

更多信息:Apple 文档

  • 您可能想隐藏导航栏,同时又保留“NavigationView”的功能,这是有原因的。“NavigationView”的目的不仅仅是显示导航栏。 (39认同)
  • 我想要 NavigiationView 具有在堆栈中导航的功能并能够轻松地从视图返回,我不需要初始视图上的 navigiationBar 。 (10认同)
  • 有没有一种方法可以在没有navigationView的情况下浏览视图? (2认同)
  • 这个答案没有帮助,因为导航视图会影响原始问题,因为需要导航到另一个视图。 (2认同)

Pet*_*inz 23

视图修饰符使它变得容易:

//ViewModifiers.swift

struct HiddenNavigationBar: ViewModifier {
    func body(content: Content) -> some View {
        content
        .navigationBarTitle("", displayMode: .inline)
        .navigationBarHidden(true)
    }
}

extension View {
    func hiddenNavigationBarStyle() -> some View {
        modifier( HiddenNavigationBar() )
    }
}
Run Code Online (Sandbox Code Playgroud)

例子: 在此处输入图片说明

import SwiftUI

struct MyView: View {
    var body: some View {
        NavigationView {
            VStack {
                Spacer()
                HStack {  
                    Spacer()
                    Text("Hello World!")
                    Spacer()
                }
                Spacer()
            }
            .padding()
            .background(Color.green)
            //remove the default Navigation Bar space:
            .hiddenNavigationBarStyle()
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 无法解决推送视图控制器的问题。 (8认同)
  • 这里似乎关键是修改器没有添加到 NavigationView,而是添加到内部的视图。这使得它发挥作用变得非常重要。谢谢!:-) (3认同)

Min*_*er3 14

如果您将标题设置为要删除空间的视图的内联,则不需要在具有 NavigationView 的视图上完成此操作,但也需要导航。

.navigationBarTitle("", displayMode: .inline)
Run Code Online (Sandbox Code Playgroud)

启动问题 解决方案1 然后只需更改导航栏外观

init() {
    UINavigationBar.appearance().setBackgroundImage(UIImage(), for: .default)
    UINavigationBar.appearance().shadowImage = UIImage()
}
Run Code Online (Sandbox Code Playgroud)

在包含初始 NavigationView 的视图上。 最终解决方案

如果要在屏幕之间更改外观,请更改相应视图中的外观

  • 这个解决方案很有用 (3认同)

Fem*_*keo 10

我还尝试了此页面上提到的所有解决方案,但只发现 @graycampbell 解决方案运行良好,动画效果良好。所以我试图创造一个我可以在整个应用程序中使用的价值,我可以通过hackingwithswift.com的例子在任何地方访问

我创建了一个ObservableObject类

class NavBarPreferences: ObservableObject {
    @Published var navBarIsHidden = true
}
Run Code Online (Sandbox Code Playgroud)

并将其传递给初始视图,SceneDelegate就像这样

var navBarPreferences = NavBarPreferences()
window.rootViewController = UIHostingController(rootView: ContentView().environmentObject(navBarPreferences))
Run Code Online (Sandbox Code Playgroud)

然后ContentView我们可以像这样跟踪这个 Observable 对象并创建一个链接到SomeView:

struct ContentView: View {
    //This variable listens to the ObservableObject class
    @EnvironmentObject var navBarPrefs: NavBarPreferences

    var body: some View {
        NavigationView {
                NavigationLink (
                destination: SomeView()) {
                    VStack{
                        Text("Hello first screen")
                            .multilineTextAlignment(.center)
                            .accentColor(.black)
                    }
                }
                .navigationBarTitle(Text(""),displayMode: .inline)
                .navigationBarHidden(navBarPrefs.navBarIsHidden)
                .onAppear{
                    self.navBarPrefs.navBarIsHidden = true
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后在访问第二个视图(SomeView)时,我们像这样再次隐藏它:

struct SomeView: View {
    @EnvironmentObject var navBarPrefs: NavBarPreferences

    var body: some View {
        Text("Hello second screen")
        .onAppear {
            self.navBarPrefs.navBarIsHidden = false
        }
    } 
}
Run Code Online (Sandbox Code Playgroud)

为了保持预览正常工作,将 NavBarPreferences 添加到预览中,如下所示:

struct SomeView_Previews: PreviewProvider {
    static var previews: some View {
        SomeView().environmentObject(NavBarPreferences())
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 使用 **@EnvironmentObject** 在整个应用程序中传递数据比 **@State** 更好,所以我更希望您回答更多 (2认同)

Osm*_*man 10

将以下代码放在您的 NextView 上

        .navigationBarBackButtonHidden(true)
        .navigationBarHidden(true)
Run Code Online (Sandbox Code Playgroud)

但是,在通过 NavigationLink 推送到 NextView 时,您还必须添加如下修饰符:

        NavigationLink(
            destination: NextView()
                .navigationBarTitle("")
                .navigationBarHidden(true)
        ) {
            Text("NEXT VIEW")
        }
                    
Run Code Online (Sandbox Code Playgroud)


闪电狮*_*闪电狮 10

您不需要设置标题,只需使用.stack

NavigationView {
     VStack {
         Color.cyan
      }
     .navigationBarHidden(true)
}
.navigationViewStyle(.stack)  // Here
Run Code Online (Sandbox Code Playgroud)


paw*_*222 9

SwiftUI 2

有一个专用的修饰符可以使导航栏占用更少的空间:

.navigationBarTitleDisplayMode(.inline)
Run Code Online (Sandbox Code Playgroud)

不再需要隐藏导航栏或设置其标题。

  • 这只会使导航栏变小。仍然需要将其完全删除。 (5认同)
  • 这是一个有用的解决方案,可以最大限度地减少其占用的空间,谢谢! (2认同)

Gom*_*ius 8

对我来说,我将 the.navigationBarTitle应用于 theNavigationView而 not toList是罪魁祸首。这在 Xcode 11.2.1 上对我有用:

struct ContentView: View {
    var body: some View {
        NavigationView {
            List {
                NavigationLink(destination: DetailView()) {
                    Text("I'm a cell")
                }
            }.navigationBarTitle("Title", displayMode: .inline)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

导航栏和列表顶部没有间隙

  • @AhmedSahib 问题是“如何删除 SwiftUI NavigationView 中的默认导航栏空间”,我的代码实现了这一点。 (3认同)
  • 非常好的建议。对于我的解决方案,我必须对内部列表应用两个修饰符以消除间距: .navigationBarTitle("", displayMode: .automatic) .navigationBarHidden(true) 然后在外部 NavigationView 上我必须应用: .navigationBarTitle(" TITLE”,显示模式:.inline) (3认同)

Vat*_*not 7

这是一个存在于SwiftUI蝽(仍然作为Xcode的11.2.1)。我ViewModifier根据现有答案中的代码编写了一个来解决这个问题:

public struct NavigationBarHider: ViewModifier {
    @State var isHidden: Bool = false

    public func body(content: Content) -> some View {
        content
            .navigationBarTitle("")
            .navigationBarHidden(isHidden)
            .onAppear { self.isHidden = true }
    }
}

extension View {
    public func hideNavigationBar() -> some View {
        modifier(NavigationBarHider())
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这样,“快速后退”手势就不再起作用了 (2认同)

Hop*_*ust 6

您可以像这样扩展本机View协议:

extension View {
    func hideNavigationBar() -> some View {
        self
            .navigationBarTitle("", displayMode: .inline)
            .navigationBarHidden(true)
    }
}
Run Code Online (Sandbox Code Playgroud)

然后只需调用例如:

ZStack {
    *YOUR CONTENT*
}
.hideNavigationBar()
Run Code Online (Sandbox Code Playgroud)


Rya*_*TCB 6

对我来说,这是因为我正在从现有的推送我的 NavigationView。实际上有一个在另一个里面。如果您来自 NavigationView,则无需在下一个中创建一个,因为您已经在 NavigatonView 中。