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

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

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



답변

어떤 이유로, 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의 공식 솔루션이 없으면 이것이 내가 생각 해낼 수있는 최고입니다.


답변

의 목적은 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 문서


답변

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

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


답변

나는 또한이 페이지에 언급 된 모든 솔루션을 시도했고 잘 작동하는 애니메이션과 함께 잘 작동하는 @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())
    }
}


답변

이것은 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())
    }
}


답변

다음 과 같이 기본 View 프로토콜을 확장 할 수 있습니다 .

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

그런 다음 예를 호출하십시오.

ZStack {
    *YOUR CONTENT*
}
.hideNavigationBar()


답변

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

.navigationBarTitle("", displayMode: .inline)

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

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

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

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