ฉันสิ้นสุดการเอาชนะค่าเริ่มต้นNavigationView
และNavigationLink
เพื่อให้ได้พฤติกรรมตามที่ต้องการ ดูเหมือนง่ายมากที่ฉันต้องมองสิ่งที่ SwiftUI เริ่มต้นทำ
NavigationView
ฉันห่อUINavigationController
ในแบบง่ายสุดUIViewControllerRepresentable
ที่ให้UINavigationController
มุมมองเนื้อหา SwiftUI เป็น environmentObject ซึ่งหมายความว่าNavigationLink
สามารถคว้าภายหลังได้ตราบใดที่มันอยู่ในตัวควบคุมการนำทางเดียวกัน (ตัวควบคุมมุมมองที่นำเสนอไม่ได้รับ environmentObjects) ซึ่งเป็นสิ่งที่เราต้องการอย่างแท้จริง
หมายเหตุ: NavigationView ต้องการ.edgesIgnoringSafeArea(.top)
และฉันไม่ทราบวิธีการตั้งค่าใน struct เอง ดูตัวอย่างว่า 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
ฉันสร้าง NavigationLink แบบกำหนดเองที่เข้าถึงสภาพแวดล้อม UINavigationController เพื่อผลัก UIHostingController ที่โฮสต์มุมมองถัดไป
หมายเหตุ:ฉันไม่ได้ติดตั้งselection
และisActive
SwiftUI.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 โครงการทั้งหมดของฉันเปลี่ยนไปใช้สิ่งเหล่านี้ทันที
ตัวอย่าง
ในตัวอย่างฉันแสดงการนำเสนอ modal เกินไป
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:
นี้ exposes ตัวควบคุมการนำทางไปยังทุกมุมมองภายในโดยการทำNavigationView
@EnvironmentObject var nvc: UINavigationController
วิธีในการแก้ไขปัญหานี้คือการทำให้สิ่งแวดล้อมวัตถุประสงค์ที่เราใช้เพื่อจัดการการนำทางของคลาสไฟล์ส่วนบุคคล ฉันแก้ไขสิ่งนี้ในส่วนสำคัญ: https://gist.github.com/Amzd/67bfd4b8e41ec3f179486e13e9892eeb