我最终覆盖了默认设置,NavigationView
并NavigationLink
获得了期望的行为。这看起来是如此简单,以至于我必须忽略默认SwiftUI视图所做的事情?
导航视图
我用一个UINavigationController
超级简单的方法包装了一个UIViewControllerRepresentable
,它UINavigationController
作为环境对象提供给SwiftUI内容视图。这意味着NavigationLink
以后可以抢到它,只要它在同一个导航控制器中(呈现的视图控制器不接收environmentObjects),这正是我们想要的。
注意: NavigationView需要.edgesIgnoringSafeArea(.top)
,但我还不知道如何在结构本身中进行设置。如果您的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,用于访问环境UINavigationController来推送托管下一个视图的UIHostingController。
注意:我没有实现SwiftUI.NavigationLink selection
和isActive
,因为我还不完全了解它们的作用。如果您想提供帮助,请评论/编辑。
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成为fileprivate类。我在要点中解决了这个问题:https : //gist.github.com/Amzd/67bfd4b8e41ec3f179486e13e9892eeb