나는 기본을 무시 결국 NavigationView하고 NavigationLink원하는 동작을 얻을 수 있습니다. 이것은 기본 SwiftUI보기가하는 것을 간과해야 할 정도로 단순 해 보입니다.
NavigationView
SwiftUI 컨텐츠 뷰에 environmentObject로 제공 UINavigationController하는 매우 간단한 UIViewControllerRepresentable것으로 래핑 UINavigationController합니다. 이것은 NavigationLink나중에 동일한 네비게이션 컨트롤러 (표시 된 뷰 컨트롤러가 environmentObjects를 수신하지 않음)에있는 한 정확히 우리가 원하는 것을 얻을 수 있음을 의미합니다.
참고 : NavigationView가 필요 .edgesIgnoringSafeArea(.top)하지만 구조체 자체에서 NavigationView 를 설정하는 방법을 모르겠습니다. nvc가 상단에서 잘리는 경우의 예를 참조하십시오.
struct NavigationView<Content: View>: UIViewControllerRepresentable {
var content: () -> Content
init(@ViewBuilder content: @escaping () -> Content) {
self.content = content
}
func makeUIViewController(context: Context) -> UINavigationController {
let nvc = UINavigationController()
let host = UIHostingController(rootView: content().environmentObject(nvc))
nvc.viewControllers = [host]
return nvc
}
func updateUIViewController(_ uiViewController: UINavigationController, context: Context) {}
}
extension UINavigationController: ObservableObject {}
NavigationLink
다음보기를 호스팅하는 UIHostingController를 푸시하기 위해 UINavigationController 환경에 액세스하는 사용자 정의 NavigationLink를 작성합니다.
참고 : 나는를 구현하지 않은 selection및 isActiveSwiftUI.NavigationLink가 가지고있는 나는 완전히 그들이 아직 무엇을 이해하지 않기 때문에. 도움이 필요하면 의견을 작성하십시오.
struct NavigationLink<Destination: View, Label:View>: View {
var destination: Destination
var label: () -> Label
public init(destination: Destination, @ViewBuilder label: @escaping () -> Label) {
self.destination = destination
self.label = label
}
/// If this crashes, make sure you wrapped the NavigationLink in a NavigationView
@EnvironmentObject var nvc: UINavigationController
var body: some View {
Button(action: {
let rootView = self.destination.environmentObject(self.nvc)
let hosted = UIHostingController(rootView: rootView)
self.nvc.pushViewController(hosted, animated: true)
}, label: label)
}
}
이렇게하면 SwiftUI에서 뒤로 스 와이프가 올바르게 작동하지 않는 문제가 해결되고 NavigationView 및 NavigationLink라는 이름을 사용하기 때문에 전체 프로젝트가 즉시 전환되었습니다.
예
이 예에서는 모달 프레젠테이션도 보여줍니다.
struct ContentView: View {
@State var isPresented = false
var body: some View {
NavigationView {
VStack(alignment: .center, spacing: 30) {
NavigationLink(destination: Text("Detail"), label: {
Text("Show detail")
})
Button(action: {
self.isPresented.toggle()
}, label: {
Text("Show modal")
})
}
.navigationBarTitle("SwiftUI")
}
.edgesIgnoringSafeArea(.top)
.sheet(isPresented: $isPresented) {
Modal()
}
}
}
struct Modal: View {
@Environment(\.presentationMode) var presentationMode
var body: some View {
NavigationView {
VStack(alignment: .center, spacing: 30) {
NavigationLink(destination: Text("Detail"), label: {
Text("Show detail")
})
Button(action: {
self.presentationMode.wrappedValue.dismiss()
}, label: {
Text("Dismiss modal")
})
}
.navigationBarTitle("Modal")
}
}
}
편집 : 나는 "이것은 너무 간결 해 뭔가를 간과해야합니다"로 시작했고 나는 그것을 발견했다고 생각합니다. 이것은 EnvironmentObjects를 다음보기로 전송하지 않는 것 같습니다. 기본 NavigationLink가 어떻게하는지 알지 못하므로 지금은 수동으로 필요한 다음보기로 객체를 보냅니다.
NavigationLink(destination: Text("Detail").environmentObject(objectToSendOnToTheNextView)) {
Text("Show detail")
}
편집 2 :
이렇게하면 내비게이션 컨트롤러가를 NavigationView수행하여 내부의 모든보기에 노출 됩니다 @EnvironmentObject var nvc: UINavigationController. 이를 해결하는 방법은 네비게이션을 파일 개인 클래스로 관리하는 데 사용하는 environmentObject를 만드는 것입니다. 나는 이것을 요점에서 고쳤다 : https://gist.github.com/Amzd/67bfd4b8e41ec3f179486e13e9892eeb