发布的数据更新子视图,但不更新父视图

时间:2020-07-13 19:30:18

标签: ios swift swiftui

我创建了这个示例,演示了我的应用程序遇到的问题。我有一个带有属性的视图,父视图及其本身需要使用该属性来更新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无法更新?

编辑:

这是实际应用试图显示/隐藏的内容。带有锁定符号的每一行都是子视图。

Showing the overlay that exists in the parent

如果子视图中有叠加层,则会显示以下内容

Child overlay ends up behind other views

2 个答案:

答案 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

相关问题