SwiftUI NavigiationView에서 기본 탐색 모음 공간을 제거하는 방법


83

나는 (대부분의 사람들과 마찬가지로) 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: "")
}
}

여기서 궁극적 인 목표는 이러한 셀을 클릭하여 파일 트리로 더 깊게 이동할 수 있으므로 더 깊은 탐색의 막대에 뒤로 버튼을 표시해야한다는 점에 유의하고 싶습니다. 내 초기보기 동안 상단.

답변:


132

어떤 이유로, SwiftUI 당신은 또한 설정해야합니다 .navigationBarTitle위해 .navigationBarHidden제대로 작동하려면.

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

최신 정보

@Peacemoon이 주석에서 지적했듯이, 설정 여부에 관계없이 탐색 스택에서 더 깊이 탐색 할 때 탐색 모음은 숨겨진 상태로 유지 navigationBarHidden됩니다.false 다음 뷰에. 내가 의견에서 말했듯이, 이것은 애플 측의 잘못된 구현의 결과이거나 또는 끔찍한 문서 (이 작업을 수행하는 "올바른"방법이있을 수 있음을 아는 사람)입니다.

어떤 경우이든 원본 포스터가 원하는 결과를 얻을 수있는 해결 방법을 생각해 냈습니다. 불필요하게 엉망인 것 같아서 추천하길 주저하지만, 내비게이션 바를 숨기고 숨기는 간단한 방법이 없다면 이것이 제가 할 수있는 최선의 방법입니다.

이 예에서는 세 가지보기를 사용합니다.- 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탐색 스택에 깊은 뷰가 제대로 원래 설정하는 것이보기의 기본 설정 오버라이드 (override)하지 않는 것 navigationBarHidden까지를 true(가) 단지 내가 가진 원래 뷰의 환경 설정을 변경하는 바인딩을 사용하고 있었다 올 수있는 해결 방법, 그래서 때 새를 보기가 탐색 스택으로 푸시됩니다.

내가 말했듯이 이것은 해키 솔루션이지만 Apple의 공식 솔루션이 없으면 이것이 내가 생각 해낼 수있는 최고입니다.


5
이것은 내 문제를 해결했습니다! 그건 ... 당신이 탐색 모음을 숨길 수 있습니다 전에 제목을 가지고있는 것이 매우 이상하다
Vapidant

5
버그 베타의 외부가 여전히 : /
다니엘 라이언

1
@Peacemoon 나는 전에 그것을 알지 못했습니다. 대체로 Apple의 구현이 여기에서 꽤 엉성한 것처럼 느껴집니다. 당신과 함께 시작하는 줄을 숨기 그냥 제목을 설정해야하고, 설정하지 않아야 navigationBarHiddenfalse탐색 모음을 숨기기를 취소해야 다음보기에,하지만하지 않습니다. 나는 궁극적으로 SwiftUI가 얼마나 잘못 문서화되어 있는지에 질려서 UIKit으로 돌아 갔고, 적어도 20 명이 네비게이션 바를 숨기는 방법을 배우기 위해 여기에 왔다는 사실은 Apple의 구현 및 / 또는 문서에 대해 매우 좋지 않습니다. 더 나은 답변이 없어서 죄송합니다.
graycampbell

2
@SambitPrakash 전에는 NavigationView 내부에 TabView를 실제로 중첩 한 적이 없으며 Apple은 내가 말할 수있는 한 앱에서 그런 방식으로 중첩하지 않는 것 같습니다. NavigationView 내부에 TabView를 중첩하는 것이 전혀 수행되도록 의도 된 것인지 완전히 명확하지 않았으며 SwiftUI에 이러한 방식으로 중첩 할 때 나타나는 이상한 버그가 있다는 것을 알고 있습니다. TabView는 항상 NavigationViews보다 더 높은 수준의 탐색 형식처럼 느껴졌습니다. 대신 TabView 내부에 NavigationView를 중첩하면 내 해결 방법이 여전히 작동해야한다고 생각합니다.
graycampbell

2
@kar이 답변이 여전히 관심과 찬성표를 받고 있다는 것은 실망 스럽습니다. 나는 일시적인 버그에 대한 임시 해결책으로 작성했습니다. 최근에 테스트하지 않았지만 분명히 많은 문제가 있습니다. 또한 여러 사람이 NavigationView를 사용하지 않고보기 사이를 탐색 할 수 있는지 물었습니다. 대답은 '예'이지만 본질적으로 처음부터 고유 한 NavigationView를 작성해야합니다. 마술처럼보기 사이를 이동할 수는 없습니다. 무언가가 이러한 뷰를 관리하고 이들 사이에 전환을 제공해야하므로 NavigationView가 있습니다.
graycampbell

17

의 목적은 NavigationView보기 위에 탐색 모음을 추가하는 것입니다. iOS에는 대형 및 표준의 두 가지 탐색 막대가 있습니다.

여기에 이미지 설명 입력

탐색 모음을 원하지 않는 경우 :

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 문서


26
.NET Framework의 기능을 유지하면서 탐색 모음을 숨기려는 이유가 있습니다 NavigationView. 의 목적은 NavigationView탐색 모음을 표시하는 것뿐이 아닙니다.
graycampbell

6
스택에서 탐색하고보기에서 쉽게 돌아갈 수있는 기능을 위해 NavigiationView를 원합니다. 초기보기에 navigiationBar가 필요하지 않습니다.
Vapidant

2
navigationView없이보기를 탐색하는 방법이 있습니까?
user1445685

원래. 아니요. 아직 swiftui에 없습니다
Gustavo Parrado

이 답변은 NavigationView가 다른보기로 이동하는 데 필요하므로 원래 질문에 영향을 미치므로 도움이되지 않습니다.
JaseTheAce

14

보기 수정자를 사용 하면 다음과 같이 쉽게 수행 할 수 있습니다.

//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
푸시 된 뷰 컨트롤러에 대한 문제를 해결하지 않습니다.
damjandd

수정자가 NavigationView에 추가되지 않고 내부 뷰에 추가되는 것이 핵심 인 것 같습니다. 이것은 그것이 작동하는 모든 차이를 만들었습니다. 감사! :-)
JaseTheAce

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

그런 다음 두 번째 뷰 (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 보다 앱 전체에 데이터를 전달하는 것이 훨씬 낫 습니다 . 따라서 더 많은 답변을
원합니다

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

6

공간을 제거하려는 뷰의 제목을 인라인으로 설정하면 NavigationView가있는 뷰에서이 작업을 수행 할 필요가 없지만 탐색 된 뷰에서도 수행 할 수 있습니다.

.navigationBarTitle("", displayMode: .inline)

시작 문제 솔루션 1 그런 다음 탐색 모음 모양을 변경하기 만하면됩니다.

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

초기 NavigationView를 보유하는보기에서. 마지막 해결책

화면에서 화면으로 모양을 변경하려면 적절한보기에서 모양을 변경하십시오.


이 솔루션은 유용합니다
Murilo Medeiros

4

나를 위해, 나는을 적용하고 .navigationBarTitle받는 사람 NavigationView과하지에이 List범인이었다. 이것은 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)
        }
    }
}

상단에 간격이없는 탐색 모음 및 목록


5
질문과 무관
Ahmed Sahib

3
@AhmedSahib 질문은 "SwiftUI NavigiationView에서 기본 탐색 모음 공간을 제거하는 방법"이었고 내 코드는이를 수행합니다.
Genki

1
훌륭한 조언. 내 솔루션의 경우 공백을 제거하기 위해 내부 목록에 두 가지 수정자를 적용해야했습니다. .navigationBarTitle ( "", displayMode : .automatic) .navigationBarHidden (true) 그런 다음 외부 NavigationView에서 적용해야했습니다. .navigationBarTitle ( " TITLE ", displayMode : .inline)
Frankenstein

3

나에게는 기존의 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
                }
        }
    }
}

탐색하는보기의 뒤로 버튼 옆에 표시되므로 제목을 설정해야합니다.


0

@Vatsal Manot이 제시 한 아이디어를 정말 좋아했습니다 . 수정 자 이름 자체가 탐색 모음을 숨기는 것을 제안하므로 그의 대답에서 속성을
제거 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를 숨겼습니다. 참고이 간단한 예를 들어, 내가 사용하는 것이 @State@BindingUI가 가시성을 관리 할 수 있지만 이러한 환경 개체로 더 복잡한 무언가를 사용할 수 있습니다.

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

Log In 버튼을 누르면 초기 페이지가 사라지고 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 아님)에 두 가지 수정자를 적용했습니다.

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

외부 NavigationView에서 적용한 다음 .navigationBarTitle("TITLE")제목을 설정합니다.


1
아무것도하지 않습니다.
TruMan1

0

SwiftUI 2

탐색 바의 공간을 덜 차지하는 전용 수정자가 있습니다.

.navigationBarTitleDisplayMode(.inline)

더 이상 탐색 표시 줄을 숨기거나 제목을 설정할 필요가 없습니다.


-7

퍼팅 시도 NavigationView내부를 GeometryReader.

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

NavigationView루트 뷰일 때 이상한 동작을 경험했습니다 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.