Ho finito per ignorare l'impostazione predefinita NavigationView
e NavigationLink
per ottenere il comportamento desiderato. Sembra così semplice che devo trascurare qualcosa che fanno le viste predefinite di SwiftUI?
NavigationView
Lo avvolgo UINavigationController
in un super semplice UIViewControllerRepresentable
che dà UINavigationController
alla vista del contenuto SwiftUI come ambienteObject. Ciò significa che la NavigationLink
lattina può afferrarla successivamente fintanto che si trova nello stesso controller di navigazione (i controller di visualizzazione presentati non ricevono l'ambienteObjects) che è esattamente ciò che vogliamo.
Nota: NavigationView ha bisogno .edgesIgnoringSafeArea(.top)
e non so ancora come impostarlo nella struttura stessa. Vedi esempio se il tuo nvc viene tagliato in alto.
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
Creo un NavigationLink personalizzato che accede agli ambienti UINavigationController per inviare un UIHostingController che ospita la vista successiva.
Nota: Non ho implementato il selection
e isActive
quello che SwiftUI.NavigationLink ha perché non capisco ancora esattamente cosa fanno. Se vuoi aiutarti, commenta / modifica.
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)
}
}
Questo risolve il back swipe che non funziona correttamente su SwiftUI e poiché utilizzo i nomi NavigationView e NavigationLink, il mio intero progetto è passato immediatamente a questi.
Esempio
Nell'esempio mostro anche una presentazione modale.
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")
}
}
}
Modifica: ho iniziato con "Sembra così semplice che devo trascurare qualcosa" e penso di averlo trovato. Questo non sembra trasferire EnvironmentObjects alla vista successiva. Non so come lo fa il NavigationLink predefinito, quindi per ora invio manualmente gli oggetti alla vista successiva dove ne ho bisogno.
NavigationLink(destination: Text("Detail").environmentObject(objectToSendOnToTheNextView)) {
Text("Show detail")
}
Modifica 2:
Questo espone il controller di navigazione a tutte le viste all'interno NavigationView
facendo @EnvironmentObject var nvc: UINavigationController
. Il modo per risolvere questo problema è rendere environmentObject che utilizziamo per gestire la navigazione in una classe privata di file. Ho risolto questo in sintesi: https://gist.github.com/Amzd/67bfd4b8e41ec3f179486e13e9892eeb