使用@State 变量不适用于从子视图更改 Body 中的视图状态

时间:2021-06-20 12:44:38

标签: ios swift swiftui

假设在我的 iOS SwiftUI 应用中有一个简单的 ContentView,里面有两个视图。

对 ContentView 的引用可用于代码的其他部分。

从那里用户想要确定显示两个视图中的哪一个,即一个、一个或两个都没有。

那个代码有点像

contentViewReference.setView1Visible(view1Visible:true) //or false

这是内容视图

struct ViewsState
{
    var view1Visible:Bool
    var view2Visible:Bool
    init(view1Visible:Bool,view2Visible:Bool)
       {
          self.view1Visible=view1Visible
          self.view2Visible=view2Visible
       }
 }

struct ContentView: View 
{ 
    @State private var viewsState:ViewsState=ViewsState(view1Visible:true,view2Visible:false)

    
    public func setView1Visible(view1Visible:Bool)
        {
          viewsState.view1Visible=view1Visible
        }

    public func setView2Visible(view2Visible:Bool)
        {
          viewsState.view2Visible=view2Visible
        }

    var body: some View 
    {
        if (viewsState.view1Visible) {View1}
        if (viewsState.view1Visible) {View2}
    }
}

但是视图的可见性永远不会改变,为什么?

我不认为我需要绑定,因为状态“真相”在 ContentView 中,但它是通过公共函数分配的。

没有父视图,切换代码确实在作为视图 1 一部分的菜单内。

但是在调用时

setView1Visible(view1Visible:false)

比如没有效果,View1不会变成隐藏。

这只是一段代码。 Real ContentView 稍微复杂一些,但问题没有改变。

3 个答案:

答案 0 :(得分:0)

@P5music,没有足够的代码来复制您的问题并正确调查。 我也不知道你是怎么得到的:

   contentViewReference.setView1Visible(view1Visible:true) 

以下是对您的代码的一些观察。

    @State private var viewsState:ViewsState(view1Visible:true,view2Visible:false)

应该

    @State var viewsState = ViewsState(view1Visible:true,view2Visible:false)

你可能还想要:

    var body: some View 
{
    if (viewsState.view1Visible) {View1}
    if (viewsState.view2Visible) {View2}  // <--- here 
}

另外,“...确定显示两个视图中的哪个”,这意味着每次设置 "view1Visible" 为某个值,同时您还需要将 "view2Visible" 设置为相反的值。

答案 1 :(得分:0)

class ViewsState: ObservableObject
{
    @Published var view1Visible:Bool
    @Published var view2Visible:Bool
    init(view1Visible:Bool,view2Visible:Bool)
    {
        self.view1Visible=view1Visible
        self.view2Visible=view2Visible
    }
    public func setView1Visible(view1Visible:Bool)
    {
        self.view1Visible = view1Visible
        view2Visible = !view1Visible
    }
    
    public func setView2Visible(view2Visible:Bool)
    {
        self.view2Visible = view2Visible
        view1Visible = !view2Visible
    }
}

struct ViewStateView: View {
    @StateObject private var viewsState: ViewsState = ViewsState(view1Visible:true,view2Visible:false)

    var body: some View
    {
        VStack{
            if (viewsState.view1Visible) {Text("View1")}
            if (viewsState.view2Visible) {Text("View2")}
            SomeOtherView().environmentObject(viewsState)
        }
    }
}
struct SomeOtherView: View {
    @EnvironmentObject var viewsState: ViewsState
    var body: some View
    {
        VStack{
            Text("SomeOtherView")
            Button("change state view 1", action: {
                viewsState.setView1Visible(view1Visible:false)
            })
            Button("change state view 2", action: {
                viewsState.setView2Visible(view2Visible:false)
            })
        }
        
    }
}
struct ViewStateView_Previews: PreviewProvider {
    static var previews: some View {
        ViewStateView()
    }

答案 2 :(得分:0)

假设您的“contentViewReference.setView1Visible(view1Visible:true)”有效,则如下 测试代码似乎有效:

import SwiftUI

@main
struct TestApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

struct ViewsState{
    var view1Visible:Bool
    var view2Visible:Bool
    init(view1Visible:Bool, view2Visible:Bool){
        self.view1Visible = view1Visible
        self.view2Visible = view2Visible
    }
}

struct ContentView: View {
    @State var viewsState = ViewsState(view1Visible:true, view2Visible:false)
    
    public func setView1Visible(view1Visible:Bool){
        viewsState.view1Visible = view1Visible
        viewsState.view2Visible = !view1Visible
    }
    
    public func setView2Visible(view2Visible:Bool){
        viewsState.view2Visible = view2Visible
        viewsState.view1Visible = !view2Visible
    }
    
    var body: some View {
        VStack {
            Button("change view") {
                if viewsState.view1Visible {
                    setView1Visible(view1Visible: false)
                } else {
                    setView1Visible(view1Visible: true)
                }
            }
            if (viewsState.view1Visible) {View1()}
            if (viewsState.view2Visible) {View2()}
        }
    }
}

struct View1: View {
    var body: some View {
        Text("View1")
    }
}

struct View2: View {
    var body: some View {
        Text("View2")
    }
}