SwiftUI 将数据从 UIViewRepresentable 传递给 SwiftUI 的 View
Posted
技术标签:
【中文标题】SwiftUI 将数据从 UIViewRepresentable 传递给 SwiftUI 的 View【英文标题】:SwiftUI pass data from UIViewRepresentable to SwiftUI's View 【发布时间】:2020-10-18 11:28:53 【问题描述】:我正在编写一个自定义滚动视图来启用图像缩放和定位。由于它将在 SwiftUI 视图中使用,因此我符合 UIViewRepresentable
。我正在尝试获取滚动视图的zoomScale
属性以及contentOffset
,以便准确确定图像的外观(当前已缩放和定位)。如果图像没有缩放或定位不同,通常这将是 1.0 和 (0,0)。
我面临的问题是,如果我将绑定传递到在缩放比例更改或 contentOffset 更改时更改的视图中,则重新绘制视图(因为刷新支持 @State)。这会导致诸如“在更新视图时更新状态”错误等问题。
以及再次调用 makeUIView
时重置的 contentOffset 和缩放比例。如果我也在那里重用这些值,我们几乎会陷入事件循环。
Scale changes -> Binding changes -> State changes -> Redraw UI -> Scale changes ...
当数据在 SwiftUI 中发生变化时,有什么方法可以将数据从视图中传递出去而不刷新? ViewPreferences 呢?他们可以工作吗?
当“超级视图”中任何其他不相关的@State 更改时,会出现另一个问题,缩放和 contentOffset 被重置,所以我需要将绑定传递给该视图。
谢谢
【问题讨论】:
听起来你的代码有bug,因为makeUIView
不应该在可表示的绑定发生变化时被调用,只有updateUIView
,所以你会提供你的代码吗?
【参考方案1】:
我发现的一种方法是向您的协调器添加一个“shouldUpdateState”布尔值。
当比例发生变化时,将 shouldUpdateState 设置为 false。
然后设置你的绑定。
updateUIView 方法的第一行应该是
guard context.coordinator.shouldUpdateState else
context.coordinator.shouldUpdateState = true
return
这是一种 hacky 解决方案......不幸的是,似乎没有任何好的方法来管理它。
另一种可能有效的替代方法(我没有测试过)是使用像这样的可观察对象。
class ViewModel: ObservableObject
@Published var zoomScale: CGFloat
在你的 UIViewRepresentable 中
// Note we aren't using @ObservedObject here.
// It shouldn't trigger view reloads when you update your viewModel.
// But it will still trigger them in your swiftUI views.
var viewModel: ObservableObject<ViewModel>
init(viewModel: ObservableObject<ViewModel>)
self._viewModel = viewModel
【讨论】:
以上是关于SwiftUI 将数据从 UIViewRepresentable 传递给 SwiftUI 的 View的主要内容,如果未能解决你的问题,请参考以下文章
SwiftUI – 将数据从 SwiftUIView 传递到 SceneKit
将数据从委托 Swift 类传递到 SwiftUI 结构中的 EnvironmentObject