交互式弹出手势识别器应允许用户在滑过屏幕的一半以上(或这些行周围的内容)时返回导航堆栈中的上一个视图。在SwiftUI中,如果滑动距离不够远,手势不会被取消。
SwiftUI: https ://imgur.com/xxVnhY7
UIKit: https ://imgur.com/f6WBUne
题:
使用SwiftUI视图时能否获得UIKit行为?
尝试次数
我试图将UIHostingController嵌入UINavigationController内,但其行为与NavigationView完全相同。
struct ContentView: View {
var body: some View {
UIKitNavigationView {
VStack {
NavigationLink(destination: Text("Detail")) {
Text("SwiftUI")
}
}.navigationBarTitle("SwiftUI", displayMode: .inline)
}.edgesIgnoringSafeArea(.top)
}
}
struct UIKitNavigationView<Content: View>: UIViewControllerRepresentable {
var content: () -> Content
init(@ViewBuilder content: @escaping () -> Content) {
self.content = content
}
func makeUIViewController(context: Context) -> UINavigationController {
let host = UIHostingController(rootView: content())
let nvc = UINavigationController(rootViewController: host)
return nvc
}
func updateUIViewController(_ uiViewController: UINavigationController, context: Context) {}
}
Run Code Online (Sandbox Code Playgroud)
我最终覆盖了默认值NavigationView
并NavigationLink
获得了所需的行为。这看起来很简单,我一定忽略了默认 SwiftUI 视图所做的事情?
我将 a 包装UINavigationController
在一个超级简单的文件中UIViewControllerRepresentable
,将UINavigationController
SwiftUI 内容视图作为环境对象提供。这意味着NavigationLink
只要它位于同一个导航控制器中(呈现的视图控制器不接收环境对象),稍后就可以获取它,这正是我们想要的。
注意: 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 {}
Run Code Online (Sandbox Code Playgroud)
我创建了一个自定义的 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)
}
}
Run Code Online (Sandbox Code Playgroud)
这解决了向后滑动在 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()
}
}
}
Run Code Online (Sandbox Code Playgroud)
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")
}
}
}
Run Code Online (Sandbox Code Playgroud)
编辑:我一开始就说“这看起来很简单,我一定是忽略了一些东西”,我想我找到了它。这似乎没有将环境对象转移到下一个视图。我不知道默认的 NavigationLink 是如何做到这一点的,所以现在我手动将对象发送到我需要它们的下一个视图。
NavigationLink(destination: Text("Detail").environmentObject(objectToSendOnToTheNextView)) {
Text("Show detail")
}
Run Code Online (Sandbox Code Playgroud)
编辑2:
NavigationView
这通过执行以下操作将导航控制器公开给内部的所有视图@EnvironmentObject var nvc: UINavigationController
。解决这个问题的方法是使我们用来管理导航的environmentObject成为一个文件私有类。我在要点中修复了这个问题:https://gist.github.com/Amzd/67bfd4b8e41ec3f179486e13e9892eeb
归档时间: |
|
查看次数: |
657 次 |
最近记录: |