ios - UIViewControllerRepresentable 包装在 AnyView 中时无法正常工作

标签 ios swift swiftui

我使用 UIViewControllerRepresentable 创建了这个非常简单的包装器:

struct ViewControllerWrapperView: UIViewControllerRepresentable {
    let controller: UIViewController

    func makeUIViewController(context: UIViewControllerRepresentableContext<ViewControllerWrapperView>) -> UIViewController {
        return controller
    }

    func updateUIViewController(_ uiViewController: UIViewController, context: UIViewControllerRepresentableContext<ViewControllerWrapperView>) {}
}

使用它在 SwiftUI View 中显示 ViewController 效果很好:

struct ContentView: View {
    @State private var viewSwitch: Bool = true

    let blueView: ViewControllerWrapperView = {
        let blueViewController = UIViewController()
        blueViewController.view.backgroundColor = .blue
        return ViewControllerWrapperView(controller: blueViewController)
    }()

    let redView: ViewControllerWrapperView = {
        let redViewController = UIViewController()
        redViewController.view.backgroundColor = .red
        return ViewControllerWrapperView(controller: redViewController)
    }()

    var body: some View {
        Button("Switch") { viewSwitch.toggle() }

        if viewSwitch {
            blueView
        } else {
            redView
        }
    }
}

但是一旦我将 ViewControllerWrapperView 包装在 AnyView 中,它们就会停止正常工作:

struct ContentView: View {
    @State private var viewSwitch: Bool = true

    let blueView: AnyView = {
        let blueViewController = UIViewController()
        blueViewController.view.backgroundColor = .blue
        return AnyView(ViewControllerWrapperView(controller: blueViewController))
    }()

    let redView: AnyView = {
        let redViewController = UIViewController()
        redViewController.view.backgroundColor = .red
        return AnyView(ViewControllerWrapperView(controller: redViewController))
    }()

    var body: some View {
        Button("Switch") { viewSwitch.toggle() }

        if viewSwitch {
            blueView
        } else {
            redView
        }
    }
}

使用AnyView,点击按钮时 View 不会切换。更深入地研究一下,我发现了以下内容:

对于首次显示 View 时的两种情况:

  1. 在蓝色 View 的 ViewControllerWrapperView 上调用 makeUIViewController
  2. updateUIViewController 在蓝色 View 的 ViewControllerWrapperView 上调用,参数 uiViewController 是蓝色 ViewController。

现在,如果没有 AnyView,当点击切换按钮时,UIViewControllerRepresentable 的生命周期将按预期执行:

  1. updateUIViewController 在蓝色 View 的 ViewControllerWrapperView 上调用,参数 uiViewController 是蓝色 ViewController。
  2. 在红色 View 的 ViewControllerWrapperView 上调用 makeUIViewController
  3. 在红色 View 的ViewControllerWrapperView上调用updateUIViewController,参数uiViewController是红色ViewController。
  4. dismantleUIViewController 被调用,参数 uiViewController 是蓝色 View 。

但是使用AnyView,当点击切换按钮时,唯一发生的事情是:

  1. updateUIViewControllerRED View 的 ViewControllerWrapperView 上调用,参数 uiViewController蓝色 View Controller 。

我是否遗漏了什么,或者这是 SwiftUI 中的一个错误?

最佳答案

Am I missing something or is this a bug in SwiftUI?

这不是一个错误,AnyView 消除了类型差异,因此渲染 body SwiftUI 引擎只会看到 AnyView 替换为 AnyView 相等,因此引擎不会替换现有 View ,而只是刷新它(因为状态已更改),从而导致 updateUIViewController 调用。一切都如预期。

这就是为什么使用 AnyView 应该非常非常小心和有意义,并清楚地了解过程和后果。

关于ios - UIViewControllerRepresentable 包装在 AnyView 中时无法正常工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73151408/

相关文章:

ios - 从 'CLLocation?' 向下转换为 'CLLocation' 仅解开可选值;您的意思是使用 '!' 吗?

ios - 如何在 SwiftUI 中点击 ActionSheet.Button 后呈现 View ?

SwiftUI:是否存在修饰符来突出显示 Text() View 的子字符串?

iOS Game Center 提交 float 而不是 int64_t

ios - 带有可折叠侧边栏菜单的 UITapGestureRecognizer Swift

html - iOS Safari HTML 表单下一个/上一个按钮 - 它们如何工作?

swift - 在程序开始时,RealmSwift 现有对象的数量始终为 4

foreach - 如何使用 SwiftUI 在 ScrollView 中选择一个项目?

ios - 为什么setEditing :animated: and insertRowsAtIndexPaths: result in this weird editing style animation?

iOS – 本地化的 JSON 资源