在 SwiftUI 中的 2 个子视图之间共享 @State var Bool

Sharing a @State var Bool between 2 child Views in SwiftUI

我是一名设计师,我正在努力学习 SwiftUI 以获取乐趣,同时也确保我更多地了解我的开发团队对我的需求。

还有一些非常简单的事情我做不到!

正如您从下面这段代码中看到的,我只想在 var showHello 为 true 时显示一段文本,而且效果很好。

import SwiftUI

struct ContentView: View {

    @State var showHello = true

    var body: some View {

        VStack {
            Spacer()
            Button("Show Hello", action: { showHello.toggle() })
                .padding()
            Spacer()
            Text("This is your message:")
                .padding()
            if showHello == true {
                Text("Hello")
            } else {
                Text("Hello")
                    .opacity(0)
            }
            Spacer()
        }

    }

}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

但是当我想通过使用多个视图来做完全相同的事情时,它不起作用!

// Parent file

import SwiftUI

struct ContentView: View {

    var body: some View {

        VStack {
            TopView()
            BottomView()
        }

    }

}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
// Child file 1

import SwiftUI

struct TopView: View {

    @State var showHello = true

    var body: some View {

        Button("Show Hello", action: { showHello.toggle() })
            .padding()

    }

}

struct TopView_Previews: PreviewProvider {
    static var previews: some View {
        TopView()
    }
}
// Child file 2

import SwiftUI

struct BottomView: View {

    var body: some View {

        Text("This is your message:")
        if showHello == true {
            Text("Hello")
        } else {
            Text("Hello")
                .opacity(0)
        }

    }

}

struct BottomView_Previews: PreviewProvider {
    static var previews: some View {
        BottomView()
    }
}

而且我知道我们不能从不同的视图共享一个 var,所以我在互联网上花了几个小时来了解更多关于使用 @State/@Binding 或 @EnvironmentObject 的信息,但所有的例子都是关于从一个视图共享一个 var父视图到子视图,但不是子视图之间到父视图。

此外,无论我在做什么,Xcode 总是出错,因为某处缺少某些东西!

我需要你的帮助,在此先感谢! :P

I have spent hours on Internet to learn more about using @State/@Binding or @EnvironmentObject

所以您走在正确的道路上,因为您确实需要使用 @Binding。也许你只是对如何连接点有错误的想法。

基本上,您需要 parent 或 ContentView 中的 @State 属性 包装器,因为您想在 [=] 中共享相同的 属性 35=] 视图并对它的任何突变做出反应,你在 child 视图中使用 @Binding 属性 包装器。

所以你会得到这样的东西:

struct ContentView: View {
    @State var showHello = true

    var body: some View {
        VStack {
            TopView(showHello: $showHello)
            BottomView(showHello: showHello)
        }
    }
}

struct TopView: View {
    @Binding var showHello: Bool

    var body: some View {
        Button("Show Hello", action: { showHello.toggle() })
            .padding()
    }
}

struct BottomView: View {
    let showHello: Bool

    var body: some View {
        Text("This is your message:")
        Text("Hello")
            .opacity(showHello ? 1 : 0)
        }
    
}

我会为 SwiftUI 推荐一些其他好的资源:

您不需要在此特定示例中使用 @Binding,因为您没有在子视图中更改 showHello 的状态。 @Binding 用于 two-way 数据流(即从父级到子级,反之亦然)。如果您的数据流是单向的(即从父级到子级),您可以在子视图中使用简单的 let

还有,不是这个:

if showHello == true {
    Text("Hello")
} else {
    Text("Hello")
        .opacity(0)
}

你应该这样做:

Text("Hello")
    .opacity(showHello ? 1 : 0)

第一种方法创建两个不同且独立的 View,而第二种方法创建一个 View,您可以根据需要更改其 opacity 修饰符。对于像这样的简单 View 层次结构来说没什么大不了的,但是一旦你开始获得更复杂的层次结构,它将有助于 SwiftUI 的视图差异和 re-rendering。它有助于动画,因为它是一个 View 上的 属性 正在改变而不是两个 View 切换出来。

这样也更容易阅读。

好的,一切正常。感谢你们所有人,尤其是@NicolasElPapu。

此外,该解决方案适用于模拟器,但不适用于 PreviewProviders。如果你还是像我一样报错,只需更新底部的这些代码即可。

struct TopView_Previews: PreviewProvider {
    static var previews: some View {
        TopView(showHello: .constant(true))
    }
}
struct BottomView_Previews: PreviewProvider {
    static var previews: some View {
        BottomView(showHello: true) // Or .constant(true) again if you're not using a let for the BottomView!
    }
}

此外,如果您想了解为什么需要在 PreviewProvider 中添加虚假信息,原因如下:https://www.hackingwithswift.com/forums/swiftui/binding-variable-won-t-preview/10974

再次感谢大家!