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

将数据从委托 Swift 类传递到 SwiftUI 结构中的 EnvironmentObject

SwiftUI 将数据从 Firebase 加载到 TextView

无法将数据从 Firebase 附加到数组 SwiftUI

将数据从模型传递到 SwiftUI 中的视图