gpt4 book ai didi

ios - 如何在 SwiftUI 中恢复与 UIKit (interactivePopGestureRecognizer) 中相同的行为

转载 作者:行者123 更新时间:2023-12-02 03:10:08 25 4
gpt4 key购买 nike

交互式弹出手势识别器应允许用户在滑动超过一半屏幕(或这些线周围的某些内容)时返回导航堆栈中的上一个 View 。在 SwiftUI 中,当滑动距离不够远时,手势不会被取消。

SwiftUI: /image/shQl8.jpg

UIKit: /image/2EeIS.jpg

<小时/>

问题:

使用 SwiftUI View 时是否可以获取 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) {}
}

最佳答案

我最终覆盖了默认的 NavigationViewNavigationLink 以获得所需的行为。这看起来很简单,我一定忽略了默认 SwiftUI View 所做的事情?

导航 View

我将 UINavigationController 包装在一个 super 简单的 UIViewControllerRepresentable 中,它将 UINavigationController 作为环境对象提供给 SwiftUI 内容 View 。这意味着 NavigationLink 稍后可以获取它,只要它位于同一个导航 Controller 中(呈现的 View Controller 不接收环境对象),这正是我们想要的。

注意: 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 以推送托管下一个 View 的 UIHostingController。

注意:我没有实现 SwiftUI.NavigationLink 的 selectionisActive ,因为我不完全理解它们的含义还没有做。如果您想提供帮助,请发表评论/编辑。

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")
}
}
}
<小时/>

编辑:我一开始就说“这看起来很简单,我一定是忽略了一些东西”,我想我找到了它。这似乎没有将环境对象转移到下一个 View 。我不知道默认的 NavigationLink 是如何做到这一点的,所以现在我手动将对象发送到我需要它们的下一个 View 。

NavigationLink(destination: Text("Detail").environmentObject(objectToSendOnToTheNextView)) {
Text("Show detail")
}

编辑2:

这通过执行 @EnvironmentObject var nvc: UINavigationController 将导航 Controller 公开给 NavigationView 内的所有 View 。解决这个问题的方法是使我们用来管理导航的environmentObject成为一个文件私有(private)类。我在要点中修复了这个问题:https://gist.github.com/Amzd/67bfd4b8e41ec3f179486e13e9892eeb

关于ios - 如何在 SwiftUI 中恢复与 UIKit (interactivePopGestureRecognizer) 中相同的行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58234142/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com