Saya akhirnya mengabaikan default NavigationView
dan NavigationLink
untuk mendapatkan perilaku yang diinginkan. Ini kelihatannya sangat sederhana sehingga saya harus mengabaikan sesuatu yang dilakukan oleh tampilan SwiftUI default?
NavigationView
Saya membungkus dengan UINavigationController
super sederhana UIViewControllerRepresentable
yang memberikan UINavigationController
tampilan konten SwiftUI sebagai environmentObject. Ini berartiNavigationLink
nantinya dapat mengambil bahwa selama itu di pengontrol navigasi yang sama (pengontrol tampilan yang disajikan tidak menerima objek environment) yang persis apa yang kita inginkan.
Catatan: NavigationView perlu .edgesIgnoringSafeArea(.top)
dan saya belum tahu cara mengaturnya di struct sendiri. Lihat contoh jika nvc Anda terpotong di atas.
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 {}
NavigasiLink
Saya membuat NavigationLink khusus yang mengakses lingkungan UINavigationController untuk mendorong UIHostingController yang menjadi hosting tampilan berikutnya.
Catatan: Saya belum mengimplementasikan selection
dan isActive
yang dimiliki SwiftUI.NavigationLink karena saya belum sepenuhnya mengerti apa yang mereka lakukan. Jika Anda ingin membantu dengan itu, silakan komentar / edit.
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)
}
}
Ini menyelesaikan gesekan kembali tidak berfungsi dengan benar pada SwiftUI dan karena saya menggunakan nama NavigationView dan NavigationLink seluruh proyek saya segera beralih ke ini.
Contoh
Dalam contoh saya menunjukkan presentasi modal juga.
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")
}
}
}
Sunting: Saya mulai dengan "Ini tampak sangat sederhana sehingga saya harus mengabaikan sesuatu" dan saya pikir saya menemukannya. Ini sepertinya tidak mentransfer EnvironmentObjects ke tampilan berikutnya. Saya tidak tahu bagaimana NavigationLink standar melakukannya sehingga untuk saat ini saya secara manual mengirim objek ke tampilan berikutnya di mana saya membutuhkannya.
NavigationLink(destination: Text("Detail").environmentObject(objectToSendOnToTheNextView)) {
Text("Show detail")
}
Edit 2:
Ini memperlihatkan pengontrol navigasi untuk semua tampilan di dalam NavigationView
dengan melakukan @EnvironmentObject var nvc: UINavigationController
. Cara untuk memperbaikinya adalah dengan membuat environmentObject yang kita gunakan untuk mengelola navigasi kelas pribadi-pribadi. Saya memperbaiki ini di intinya: https://gist.github.com/Amzd/67bfd4b8e41ec3f179486e13e9892eeb