【问题标题】:How to make a UIViewRepresentable @ViewBuilder work with dynamic content?如何使 UIViewRepresentable @ViewBuilder 与动态内容一起使用?
【发布时间】:2020-06-15 10:33:37
【问题描述】:

是否可以使带有ViewBuilder 参数的UIViewRepresentable 视图与ForEach 循环等动态内容一起使用?

我有以下UIViewRepresentable 视图,我用它来下拉到UIKit 并获得一些自定义UIScrollView 行为:

struct CustomScrollView<Content:View>: UIViewRepresentable {

    private let content: UIView
    private let scrollView = CustomUIScrollView()

    init(@ViewBuilder content: () -> Content) {
        self.content = UIHostingController(rootView: content()).view
        self.content.backgroundColor = .clear
    }

    func makeUIView(context: Context) -> UIView {
        scrollView.addSubview(content)
        // ...
        return scrollView
    }

    func updateUIView(_ uiView: UIView, context: Context) {}

}

这适用于静态内容,如下所示:

var body: some View {
    CustomScrollView {
        VStack {
            ForEach(1..<50) { number in
                Text(String(number))
            }
        }
    }
}

但动态内容失败,显示空白视图:

var body: some View {
    CustomScrollView {
        VStack {
            ForEach(self.numbers) { number in
                Text(String(number))
            }
        }
    }
}

我知道这是因为当makeUIView() 被调用时,我的动态数据是空的,稍后会被填充或更新。我在初始化时评估我的UIViewRepresentable 的content,而不是在updateUIView() 中更新它。


如何更新updateUIView() 中的动态子内容?我尝试将@ViewBuilder 参数捕获为@escaping 闭包并在每次调用updateUIView() 时对其进行评估,这似乎是正确的解决方案(尽管效率低下?),但到目前为止还没有运气。

【问题讨论】:

标签: ios swift uikit swiftui


【解决方案1】:

@ViewBuilder 评估失败,因为您在此处更改了错误的结构副本

func updateUIView(_ uiView: UIView, context: Context) {}

您应该直接使用content() 改变uiView 的子视图

更新的答案:删除了协调器的解决方案,因为在某些情况下它的工作方式与预期不同

【讨论】:

  • 但是没有协调员如何解决这个问题?
【解决方案2】:

以下内容可能会有所帮助。目前尚不清楚缺席CustomUIScrollView 的行为如何(可能问题就在那里),但使用标准UIScrollView 可以与动态 ForEach 一起使用。使用 Xcode 11.4 / iOS 13.4 测试

struct CustomScrollView<Content:View>: UIViewRepresentable {

    private let content: UIView
    private let scrollView = UIScrollView()

    init(@ViewBuilder content: () -> Content) {
        self.content = UIHostingController(rootView: content()).view
        self.content.backgroundColor = .clear
    }

    func makeUIView(context: Context) -> UIView {
        content.translatesAutoresizingMaskIntoConstraints = false
        scrollView.addSubview(content)
        let constraints = [
            content.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor),
            content.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor),
            content.topAnchor.constraint(equalTo: scrollView.contentLayoutGuide.topAnchor),
            content.bottomAnchor.constraint(equalTo: scrollView.contentLayoutGuide.bottomAnchor),
            content.widthAnchor.constraint(equalTo: scrollView.widthAnchor)
        ]
        scrollView.addConstraints(constraints)
        return scrollView
    }

    func updateUIView(_ uiView: UIView, context: Context) {}

}

struct TestCustomScrollView: View {
    private var items = Array(repeating: "Test", count: 50)
    var body: some View {
        CustomScrollView {
            VStack {
                ForEach(Array(items.enumerated()), id: \.0) { i, item in
                    Text("\(item) - \(i)")
                }
            }
        }
    }
}

【讨论】:

  • 什么是\.0?我得到一个范围异常。
猜你喜欢
  • 2020-01-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-07
  • 2012-03-12
  • 2022-01-18
  • 1970-01-01
相关资源
最近更新 更多