I’m a designer who’s trying to learn SwiftUI for fun and also to make sure I know a bit more what my developer’s team needs from me.
And there’s something very simple I just can’t do!
As you can see from this piece of code below, I just want to show a text when the var showHello is true, and it’s working nicely.
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()
}
}
But when I want to do the exact same thing by using multiple views, it doesn’t work!
// 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()
}
}
And I know that we can’t share a var from different views so I have spent hours on Internet to learn more about using @State/@Binding or @EnvironmentObject but all the examples are about sharing a var from a parent view to a child view but not between child views into a parent view.
Also, no matter what I’m doing, there’s always an error from Xcode because something is missing somewhere!
I need your help, thanks in advance! 😛
3
Answers
Alright, everything is working nicely. Thanks to all of you guys and especially to @NicolasElPapu.
Also, the solution is working with the simulator but not with the PreviewProviders. If you still have an error like I had, just update these pieces of code at the bottom.
Also, if you want to understand why you need to add a fake information into the PreviewProvider, here's the why: https://www.hackingwithswift.com/forums/swiftui/binding-variable-won-t-preview/10974
Thanks again guys!
So you are on the right path because you do need to use
@Binding
. Maybe you just had the wrong idea of how to connect the dots.Basically you need the
@State
property wrapper in your parent orContentView
and since you want to share that same property in your child views and react to any mutation on it, you use the@Binding
property wrapper in the child views.So you would have something like this:
I would recommend some other good resources for SwiftUI:
You don’t need to use
@Binding
in this particular example since you are not changing the state ofshowHello
in the child view.@Binding
is for two-way data flow (i.e., from the parent to the child and vice versa). If your data flow is unidirectional (i.e., from the parent to the child), you can just use a simplelet
in the child view.Also, instead of this:
You should do this:
The first way creates two different and separate
View
s whereas the second way creates a singleView
whoseopacity
modifier you change as needed. Not such a big deal with a simpleView
hierarchy like this, but once you start getting more complicated hierarchies it will help SwiftUI’s view diffing and re-rendering. And it helps with animations since it’s a property on oneView
that is changing rather than twoView
s switching out.It’s also just easier to read that way.