发布的数据更新子视图但不更新父视图
Posted
技术标签:
【中文标题】发布的数据更新子视图但不更新父视图【英文标题】:Published data updates child view but not parent view 【发布时间】:2020-07-13 19:30:18 【问题描述】:我创建了这个示例来演示我的应用程序遇到的问题。我有一个带有属性的视图,父视图及其本身需要使用它来更新 UI。发生的情况是,当属性更改时子视图会更新,而父视图不会。
我试图用下面的代码实现的是,当您点击文本时,如果状态为真,则会出现蓝色轮廓,否则没有轮廓。子视图更新(文本更改)但父视图保持不变(蓝色轮廓保持不变)的实际情况。
/********************Child View***************************/
class ExampleChildViewModel: ObservableObject
var id = UUID()
@Published var showOptions: Bool
init( _ show: Bool )
showOptions = show
struct ExampleChildView: View
@ObservedObject var model: ExampleChildViewModel
var body: some View
Text("\(String(model.showOptions))")
.onTapGesture
self.model.showOptions.toggle()
/********************Parent View***************************/
class ExampleParentViewModel: ObservableObject
@Published var children = [ExampleChildViewModel]()
init()
children.append( ExampleChildViewModel( true ) )
children.append( ExampleChildViewModel( false ) )
struct ExampleParentView: View
@ObservedObject var parent: ExampleParentViewModel
var body: some View
VStack
ForEach( parent.children, id: \.id ) m in
ExampleChildView( model: m )
.frame(width: 60, height: 30)
.overlay(
RoundedRectangle(cornerRadius: 6)
.stroke(Color.blue, lineWidth: 3)
.opacity((m.showOptions) ? 1 : 0) // <---- Doesn't update
)
/********************Main View*******************************/
struct ExampleView: View
@ObservedObject var model = ExampleParentViewModel()
var body: some View
VStack
ExampleParentView( parent: model )
为什么设置了ExampleChildViewModel
中的showOptions
时ExampleParentView
中的parent
没有得到更新?
编辑:
这是实际应用试图显示/隐藏的内容。带有锁符号的每一行都是子视图。
如果我在子视图中有叠加层,我最终会得到以下结果
【问题讨论】:
我对 SwiftUI 不是很熟悉,但我认为这是因为ExampleParentViewModel
children
只会发布对数组本身的浅层更改,而不是对其包含的对象的深层更改。跨度>
【参考方案1】:
您希望父视图负责管理每个子视图的大纲的任何原因?似乎他们应该确定自己的布局,您可以通过将叠加层移动到子视图中来做到这一点:
struct ExampleChildView: View
@ObservedObject var model: ExampleChildViewModel
var body: some View
HStack
Text("\(String(model.showOptions))")
.frame(width: 60, height: 30)
.overlay(
RoundedRectangle(cornerRadius: 6)
.stroke(Color.blue, lineWidth: 3)
.opacity((model.showOptions) ? 1 : 0))
.onTapGesture
self.model.showOptions.toggle()
【讨论】:
覆盖最终位于父视图中,因为实际上它是一个自定义上下文菜单,需要覆盖所有其他视图。当它在子视图中时,它最终在父视图中的一些其他视图下。父母最终有 N 个孩子,我希望每个孩子都能显示他们的上下文菜单。 要将上下文菜单放在所有视图之上,您可以将其放在 ZStack 中并更改其 Z 位置。 也许这很愚蠢,但我对如何更改 VStack 中的事物的 z 轴感到困惑。所以想象一个有 5 个视图的 VStack,视图 3 和 4 是这些子视图之一,其中覆盖层需要位于视图 #3、4 和 5 的顶部。我如何保持它们彼此垂直对齐并且然后在运行时将视图 3 或视图 4 移动到 ZStack 的顶部?这可能吗?【参考方案2】:这有点奇怪,为什么要在另一个视图中定义视图的外观。通常你在 View(本例中是 ChildView)本身中进行所有“调整”,然后在 ParentView 中实现它。
现在解决问题。 @Published
像 @State
一样工作。更改后,它会通知视图进行更新。这就是你的问题。它通知 ChildView 更新,但不通知 ParentView。如下修改ParentView时可以看到:
var body: some View
VStack
ForEach( self.parent.children, id: \.id ) m in
ExampleChildView( model: m )
.opacity( m.showOptions ? 1 : 0)
.frame(width: 60, height: 30)
.overlay(
RoundedRectangle(cornerRadius: 6)
.stroke(Color.blue, lineWidth: 3)
.opacity( m.showOptions ? 1 : 0)// <---- Doesn't update
)
Text("Current State?").onTapGesture
for m in self.parent.children
print(m.showOptions)
print("-----------")
您可以看到变量正在发生变化,但由于您的 ParentView 没有收到更新通知,因此它不会更新。
当在 ChildView 中定义时,false/true 文本会更新。也在 ChildView 中实现 Overlay,它的工作方式与您期望的一样:
struct ExampleChildView: View
@ObservedObject var model: ExampleChildViewModel
var body: some View
Text("\(String(model.showOptions))")
.onTapGesture
self.model.showOptions.toggle()
.overlay(
RoundedRectangle(cornerRadius: 6)
.stroke(Color.blue, lineWidth: 3)
.opacity( self.model.showOptions ? 1 : 0)
)
我建议您在视图本身中实现视图样式的全部或至少主要(更改)部分。
另外:这篇文章解释得很好 https://www.hackingwithswift.com/books/ios-swiftui/sharing-swiftui-state-with-observedobject
【讨论】:
是的,我想这个例子没有解释为什么它是这样设置的。父视图中的叠加层是一个自定义上下文菜单,它也应该位于父视图中的所有其他视图之上。大纲只是示例中查看父视图状态的一种方式。 有没有办法将状态通知从孩子“转发”给父母?以上是关于发布的数据更新子视图但不更新父视图的主要内容,如果未能解决你的问题,请参考以下文章