【问题标题】:SwiftUI : how to access UINavigationController from NavigationViewSwiftUI:如何从 NavigationView 访问 UINavigationController
【发布时间】:2020-01-22 18:43:42
【问题描述】:

我正在使用 SwiftUI 开发应用程序。该应用基于NavigationView

我正在使用提供UIKit 组件的第三方框架,该框架尚未更新以支持 SwiftUI。

一个框架方法需要UINavigationController类型的参数

如何为这个框架提供由 SwiftUI 创建的 NavigationController ?或者我如何创建一个 UINavigationController 来替换 SwiftUI 的默认值?

我阅读了https://developer.apple.com/tutorials/swiftui/interfacing-with-uikithttps://sarunw.com/posts/uikit-in-swiftui,但这些似乎解决了另一个问题:它们解释了如何在 SwiftUI 应用程序中使用 UIKit 组件。我的问题是反过来,我想使用 SwiftUI App 并访问底层 NavigationController 对象。

[更新] 本次研讨会提供了实现我的解决方案的代码:https://amplify-ios-workshop.go-aws.com/30_add_authentication/20_client_code.html#loginviewcontroller-swift

【问题讨论】:

  • 请不要仅仅因为您没有得到问题而投反对票。这是一个有效的问题。

标签: uinavigationcontroller uikit swiftui


【解决方案1】:

感谢 Yonat 的解释,我明白了如何做到这一点,这是我的解决方案,希望对其他人有所帮助。

第 1 部分:将在 Swift UI 中使用的 UI 视图控制器。它调用第三方认证库,将UINavigationControler 作为参数传递。 UINavigationController 是一个空视图,只是为了让第三方身份验证库有一个导航控制器来弹出登录屏幕。

struct LoginViewController: UIViewControllerRepresentable {

    let navController =  UINavigationController()


    func makeUIViewController(context: Context) -> UINavigationController {
        navController.setNavigationBarHidden(true, animated: false)
        let viewController = UIViewController()
        navController.addChild(viewController)
        return navController
    }

    func updateUIViewController(_ pageViewController: UINavigationController, context: Context) {
    }

    func makeCoordinator() -> Coordinator {
        return Coordinator(self)
    }

    class Coordinator: NSObject {
        var parent: LoginViewController

        init(_ loginViewController: LoginViewController) {
            self.parent = loginViewController
        }
    }

    func authenticate() {
        let app = UIApplication.shared.delegate as! AppDelegate
        let userData = app.userData

        userData.authenticateWithDropinUI(navigationController: navController)
    }

}

第 2 部分:Swift UI 视图显示(空)UINavigationControler 并在其上覆盖一个 SwiftUI 视图。

import SwiftUI

struct LandingView: View {
    @ObservedObject public var user : UserData

    var body: some View {

        let loginView = LoginViewController()

        return VStack {

            // .wrappedValue is used to extract the Bool from Binding<Bool> type
            if (!$user.isSignedIn.wrappedValue) {

                ZStack {
                    loginView
                    // build your welcome view here 
                    Button(action: { loginView.authenticate() } ) {
                        UserBadge().scaleEffect(0.5)
                    }
                }

            } else {

                // my main app view 
                // ...
            }
        }
    }
}

【讨论】:

【解决方案2】:

我认为你现在做不到。查看NavigationView 的视图调试器,我得到了下面的图像。

所以在你看来,你将不得不反其道而行之:
UINavigationController 开始,然后将 SwiftUI 视图包装在 UIHostingController 中。

【讨论】:

【解决方案3】:

我尝试做同样的事情,因为我想让 interactivePopGestureRecognizer 在整个视图上工作。

我设法使用 UINavigationController 扩展访问当前导航控制器并覆盖 viewDidAppear,检查是否启用了 interactivePopGestureRecognizer 并对其进行了更改 (https://stackoverflow.com/a/58068947/1745000)

最后我的努力毫无意义。当导航视图显示 DetailHostingController 时,它关闭了 interactivePopGestureRecognizer.isEnabled!

通过 topViewController.view 的托管视图确实包含私有类型 SwiftUI.UIGestureRecognizer 的手势识别器。虽然没有设定目标...

嵌入传统的 UINavigationController 也可能是首选,因为导航视图自己的弹出手势是不可取消的(如果您稍微拖动视图并停止,它会弹回然后关闭详细视图。

【讨论】:

    猜你喜欢
    • 2021-07-23
    • 1970-01-01
    • 2021-03-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多