我创建了这个示例,演示了我的应用程序遇到的问题。我有一个带有属性的视图,父视图及其本身需要使用该属性来更新UI。发生的情况是,当属性更改时,子视图会更新,而父视图则不会。
我想用下面的代码实现的是,当状态为true时,点击文本时会出现蓝色轮廓,否则没有轮廓。实际情况是子视图更新(文本更改),而父视图保持不变(蓝色轮廓保持不变)。
/********************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 )
}
}
}
设置了parent
中的ExampleParentView
时为什么showOptions
中的ExampleChildViewModel
无法更新?
编辑:
这是实际应用试图显示/隐藏的内容。带有锁定符号的每一行都是子视图。
如果子视图中有叠加层,则会显示以下内容
答案 0 :(得分: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()
}
}
}
答案 1 :(得分:1)
为什么要定义另一个视图的外观有点奇怪。通常,您需要在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中定义的错误/真实文本会更新。还可以在ChildView中实现叠加层,它可以按您期望的方式工作:
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