如何使 UIViewRepresentable @ViewBuilder 与动态内容一起使用?
Posted
技术标签:
【中文标题】如何使 UIViewRepresentable @ViewBuilder 与动态内容一起使用?【英文标题】:How to make a UIViewRepresentable @ViewBuilder work with dynamic content? 【发布时间】: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()
时对其进行评估,这似乎是正确的解决方案(尽管效率低下?),但到目前为止还没有运气。
【问题讨论】:
你应该看到这个github.com/Onaeem26/SwiftyUIScrollView。在这里,您可以看到如何通过“更新”处理动态内容。 【参考方案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
?我得到一个范围异常。以上是关于如何使 UIViewRepresentable @ViewBuilder 与动态内容一起使用?的主要内容,如果未能解决你的问题,请参考以下文章
无法使 UIViewRepresentable 的 CustomView 在 SwiftUI 中正常工作
如何在 SwiftUI 中使 UIViewRepresentable 在 tvOS 上具有焦点?
SwiftUI:如何调整 UIViewRepresentable 输出的大小?
如何在 UIViewRepresentable SwiftUI 中重新加载集合视图