SwiftUINavigiationViewのデフォルトのナビゲーションバースペースを削除する方法


94

私は(ほとんどの人と同じように)SwiftUIを初めて使用し、NavigationViewに埋め込んだリストの上の空白を削除する方法を見つけようとしています。

この画像では、リストの上に空白があることがわかります

現行版

私が達成したいのはこれです

理想的なバージョン

使ってみました

.navigationBarHidden(true)

しかし、これは目立った変化をもたらしませんでした。

私は現在、このようにnavigiationViewを設定しています

 NavigationView {
                FileBrowserView(jsonFromCall: URLRetrieve(URLtoFetch: applicationDelegate.apiURL))
                    .navigationBarHidden(true)
                }

ここで、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: "")
}
}

ここでの最終的な目標は、これらのセルをクリックしてファイルツリーの奥深くまで移動できるようにすることです。したがって、深いナビゲーションではバーに[戻る]ボタンを表示する必要がありますが、私の最初のビューの間にそのようにトップ。

回答:


146

何らかの理由で、SwiftUIはあなたにも設定する必要があります.navigationBarTitleのために.navigationBarHidden適切に動作します。

NavigationView {
    FileBrowserView(jsonFromCall: URLRetrieve(URLtoFetch: applicationDelegate.apiURL))
        .navigationBarTitle("")
        .navigationBarHidden(true)
}

更新

@Peacemoonがコメントで指摘しているように、後続のビューで設定navigationBarHiddenfalseたかどうかに関係なく、ナビゲーションスタックを深くナビゲートしても、ナビゲーションバーは非表示のままになります。コメントで言ったように、これはApple側の不十分な実装の結果か、単に恐ろしいドキュメントの結果です(これを達成するための「正しい」方法があるかもしれません)。

いずれにせよ、私は元のポスターの望ましい結果を生み出すように思われる回避策を思いつきました。不必要にハッキーに見えるのでお勧めするのをためらっていますが、ナビゲーションバーを表示したり非表示にしたりする簡単な方法がなければ、これが最善の方法です。

この例では、3つのビューを使用しています-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")
    }
}

設定navigationBarHiddenfalse深いナビゲーションスタック内のビューには、適切に元々設定されていることを考慮の好み上書きしていないようnavigationBarHiddenにするtrueだけで、私はときに新しい元のビューの設定を変更するために結合使っていたとまで来ることができ回避するため、ビューはナビゲーションスタックにプッシュされます。

私が言ったように、これはハッキーな解決策ですが、Appleからの公式の解決策がなければ、これは私が思いついた中で最高のものです。


5
これで私の問題は修正されました!それは...あなたはナビゲーションバーを非表示にすることができます前にタイトルを持っている必要があることは非常に奇妙である
Vapidant

5
バグは、外部のベータ版のまだそこにある:/
ダニエル・ライアン

1
@Peacemoon以前は気づかなかった。全体として、Appleからの実装はここではかなりずさんなように感じます。最初にバーを非表示にするためだけにタイトルを設定する必要はありません。次のビューでに設定navigationBarHiddenするとfalse、ナビゲーションバーが再表示されますが、そうではありません。私は最終的にSwiftUIの文書化がいかに不十分であるかにうんざりし、UIKitに戻りました。ナビゲーションバーを非表示にする方法を学ぶためだけに少なくとも20人がここに来たという事実は、Appleの実装や文書化についてはかなり不十分です。申し訳ありませんが、これ以上の回答はありません。
graycampbell

2
@SambitPrakash私はこれまでNavigationView内にTabViewを実際にネストしたことはなく、Appleは私が知る限り、それらをアプリにそのようにネストしていないようです。NavigationView内にTabViewをネストすることを意図しているかどうかは、私には完全にはわかりません。SwiftUIには、そのようにネストするとポップアップする奇妙なバグがいくつかあることを私は知っています。TabViewは、私にとって常にNavigationViewよりも高レベルのナビゲーション形式のように感じてきました。代わりに、NavigationViewをTabView内にネストした場合でも、私の回避策は機能するはずです。
graycampbell

2
@karこの回答がまだ注目を集め、賛成しているのは残念です。私はそれを一時的なバグであるはずだったものに対する一時的な解決策として書きました。最近テストしていませんが、明らかに問題がたくさんあります。また、NavigationViewを使用せずにビュー間を移動できるかどうかを尋ねる人もいます。答えは「はい」ですが、基本的には独自のNavigationViewを最初から作成する必要があります。ビュー間を魔法のようにナビゲートすることはできません。何かがそれらのビューを管理し、それらの間の遷移を提供する必要があるので、NavigationViewがあります。
graycampbell

18

aの目的は、NavigationViewビューの上にナビゲーションバーを追加することです。iOSには、大型と標準の2種類のナビゲーションバーがあります。

ここに画像の説明を入力してください

ナビゲーションバーが必要ない場合:

FileBrowserView(jsonFromCall: URLRetrieve(URLtoFetch: applicationDelegate.apiURL))

大きなナビゲーションバーが必要な場合(通常、トップレベルのビューに使用されます):

NavigationView {
    FileBrowserView(jsonFromCall: URLRetrieve(URLtoFetch: applicationDelegate.apiURL))
    .navigationBarTitle(Text("Title"))
}

標準の(インライン)ナビゲーションバー(通常はサブレベルのビューに使用されます)が必要な場合:

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

この答えがお役に立てば幸いです。

詳細:Appleドキュメント


29
の機能を維持しながら、ナビゲーションバーを非表示にする理由がいくつかありますNavigationView。aの目的は、NavigationViewナビゲーションバーを表示することだけではありません。
graycampbell

6
スタック内をナビゲートし、ビューから簡単に戻ることができる機能のためにNavigiationViewが必要です。最初のビューに、navigiationBarは必要ありません。
Vapidant

2
NavigationViewなしでビューをナビゲートする方法はありますか?
user14456 8519

基本的に。いいえ。まだswiftui上に、少なくとも
グスタボParrado

別のビューに移動する必要があるため、NavigationViewを使用すると元の質問に影響が及ぶため、この回答は役に立ちません。
JaseTheAce

16

ビュー修飾子を使用すると簡単になります。

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

例: ここに画像の説明を入力してください

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

4
プッシュされたViewControllerの問題は修正されません。
damjandd

ここで重要なのは、モディファイヤがNavigationViewに追加されるのではなく、そのすぐ内側のビューに追加されることです。これはそれを機能させるためにすべての違いをもたらしました。ありがとう!:-)
JaseTheAce

10

スペースを削除するビューのタイトルをインラインとして設定する場合、NavigationViewを使用するビューでこれを行う必要はありませんが、ナビゲートするビューでも行う必要があります。

.navigationBarTitle("", displayMode: .inline)

創刊号 解決策1 次に、ナビゲーションバーの外観を変更するだけです

init() {
    UINavigationBar.appearance().setBackgroundImage(UIImage(), for: .default)
    UINavigationBar.appearance().shadowImage = UIImage()
}

最初のNavigationViewを保持するビュー。 最終的解決

画面ごとに外観を変更したい場合は、適切なビューの外観を変更してください


1
このソリューションは便利です
MuriloMedeiros20年

9

また、このページに記載されているすべてのソリューションを試しましたが、@ Graycampbellソリューションだけが、うまく機能するアニメーションでうまく機能していることがわかりました。そこで、hackingwithswift.comの例で、どこからでもアクセスできるアプリ全体で使用できる値を作成しようとしました。

ObservableObjectクラスを作成しました

class NavBarPreferences: ObservableObject {
    @Published var navBarIsHidden = true
}

そしてそれを最初のビューに渡すSceneDelegateように

var navBarPreferences = NavBarPreferences()
window.rootViewController = UIHostingController(rootView: ContentView().environmentObject(navBarPreferences))

次に、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
            }
        }
    }
}

そして、2番目のビュー(SomeView)にアクセスすると、次のように再び非表示になります。

struct SomeView: View {
    @EnvironmentObject var navBarPrefs: NavBarPreferences

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

プレビューを機能させ続けるには、次のようにNavBarPreferencesをプレビューに追加します。

struct SomeView_Previews: PreviewProvider {
    static var previews: some View {
        SomeView().environmentObject(NavBarPreferences())
    }
}

2
使用して@EnvironmentObjectのではなく、アプリ全体でデータを渡すためにはるかに優れている@state私はあなたがより多くの答えを好むので、
Arafinラッセル

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

2
これにより、「迅速なバックに」ジェスチャーは、もはや作業していない
Urkman

6

次のようにネイティブViewプロトコルを拡張できます。

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

次に、例を呼び出します。

ZStack {
    *YOUR CONTENT*
}
.hideNavigationBar()

5

私にとって、私はに適用し.navigationBarTitleNavigationViewいましたListが、犯人ではありませんでした。これはXcode11.2.1で機能します。

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

上部に隙間のないナビゲーションバーとリスト


5
尋ねられた質問とは無関係
AhmedSahib20年

3
@AhmedSahib質問は「SwiftUINavigiationViewのデフォルトのナビゲーションバースペースを削除する方法」でしたが、私のコードはそれを実現しています。
元気

1
優れたアドバイス。私のソリューションでは、間隔を取り除くために2つの修飾子を内側のリストに適用する必要がありました:.navigationBarTitle( ""、displayMode:.automatic).navigationBarHidden(true)次に、外側のNavigationViewに適用する必要がありました:.navigationBarTitle( " TITLE "、displayMode:.inline)
フランケンシュタイン

4

私にとっては、NavigationViewを既存のものからプッシュしていたためです。事実上、一方が他方の中にあります。NavigationViewからアクセスしている場合は、すでにNavigatonView内にあるため、次の内部に作成する必要はありません。


2

@graycampbellの回答に似ていますが、少し単純です。

struct YourView: View {

    @State private var isNavigationBarHidden = true

    var body: some View {
        NavigationView {
            VStack {
                Text("This is the master view")
                NavigationLink("Details", destination: Text("These are the details"))
            }
                .navigationBarHidden(isNavigationBarHidden)
                .navigationBarTitle("Master")
                .onAppear {
                    self.isNavigationBarHidden = true
                }
                .onDisappear {
                    self.isNavigationBarHidden = false
                }
        }
    }
}

ナビゲートするビューの戻るボタンの横に表示されるため、タイトルの設定が必要です。


2

SwiftUI 2

ナビゲーションバーのスペースを節約するための専用の修飾子があります。

.navigationBarTitleDisplayMode(.inline)

ナビゲーションバーを非表示にしたり、タイトルを設定したりする必要がなくなりました。


0

@VatsalManotによって与えられたアイデアを本当に気に入りました。このための修飾子を作成します。修飾子名自体がナビゲーションバーを非表示にすることを示唆しているため、プロパティを彼の回答から
削除するisHiddenことは有用ではないと思います。

// Hide navigation bar.
public struct NavigationBarHider: ViewModifier {

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

extension View {
    public func hideNavigationBar() -> some View {
        modifier(NavigationBarHider())
    }
}

0

ユーザーがログインするとTabViewが表示されるアプリで作業しているときに、同様の問題が発生しました。

@graycampbellが彼のコメントで示唆しているように、TabViewをNavigationViewに埋め込むべきではありません。そうしないと、使用している場合でも「空白」が表示されます。 .navigationBarHidden(true)

を使用しZStackてNavigationViewを非表示にしました。この単純な例では、UIの可視性を管理するために@Stateとを使用し@Bindingていますが、環境オブジェクトなど、より複雑なものを使用したい場合があることに注意してください。

struct ContentView: View {

    @State var isHidden = false

    var body: some View {
        
        ZStack {
            if isHidden {
                DetailView(isHidden: self.$isHidden)
            } else {
                NavigationView {
                    Button("Log in"){
                        self.isHidden.toggle()
                    }
                    .navigationBarTitle("Login Page")
                }
            }
        }
    }
}

ログインボタンを押すと、最初のページが消え、DetailViewが読み込まれます。[ログアウト]ボタンを切り替えると、ログインページが再表示されます

struct DetailView: View {
    
    @Binding var isHidden: Bool
    
    var body: some View {
        TabView{
            NavigationView {
                Button("Log out"){
                    self.isHidden.toggle()
                }
                .navigationBarTitle("Home")
            }
            .tabItem {
                Image(systemName: "star")
                Text("One")
            }
        }
    }
}

0

この問題に対する私の解決策は、@ Genkiと@Frankensteinによって提案されたものと同じでした。

間隔を取り除くために、内部リスト(NavigationViewではない)に2つの修飾子を適用しました。

.navigationBarTitle("", displayMode: .automatic)
.navigationBarHidden(true) 

外側のNavigationViewで.navigationBarTitle("TITLE")、タイトルを設定するために適用されます。


1
それは何もしません。
TruMan1

-8

NavigationView中に入れてみてくださいGeometryReader

GeometryReader {
    NavigationView {
        Text("Hello World!")
    }
}

NavigationViewがルートビューだったとき、私は奇妙な振る舞いを経験しました。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.