Reputation: 1033
How do I generate a preview provider for a view which has a binding property?
struct AddContainer: View {
@Binding var isShowingAddContainer: Bool
var body: some View {
Button(action: {
self.isShowingAddContainer = false
}) {
Text("Pop")
}
}
}
struct AddContainer_Previews: PreviewProvider {
static var previews: some View {
// ERROR HERE <<<-----
AddContainer(isShowingAddContainer: Binding<Bool>()
}
}
In Code above, How to pass a Binding<Bool>
property in an initialiser of a view?
Upvotes: 63
Views: 19774
Reputation: 119292
You can use the @Previewable
macro inside the #Preview
body to use @State
directly like:
#Preview {
@Previewable @State var toggle = true
AddContainer(isShowingAddContainer: $toggle)
}
Note that this new macro needs iOS 18 and macOS 15, but it seems no issue to me because it is just a preview on the code.
Upvotes: 2
Reputation: 2586
If, for some reason, you don't want the state variable to be static
as suggested by nine stones, you can also make your preview struct conform to the View
protocol in addition to the PreviewProvider
protocol.
struct AddContainer_Previews: PreviewProvider, View {
@State var isShowingAddContainer: Bool = false
static var previews: some View {
Self()
}
var body: some View {
AddContainer(isShowingAddContainer: $isShowingAddContainer)
}
}
This works by making previews
an instance of itself, which has access to the non-static variable.
Upvotes: 2
Reputation: 7910
Both other solutions [the "static var" variant AND the "constant(.false)"-variant work for just seeing a preview that is static. But you cannot not see/watch the changes of the value intended by the button action, because you get only a static preview with this solutions.
If you want to really watch (in the life preview) this changing, you could easily implement a nested view within the PreviewProvider, to - let's say - simulate the binding over two places (in one preview).
import SwiftUI
struct BoolButtonView: View {
@Binding var boolValue : Bool
var body: some View {
VStack {
Text("The boolValue in BoolButtonView = \(boolValue.string)")
.multilineTextAlignment(.center)
.padding()
Button("Toggle me") {
boolValue.toggle()
}
.padding()
}
}
}
struct BoolButtonView_Previews: PreviewProvider {
// we show the simulated view, not the BoolButtonView itself
static var previews: some View {
OtherView()
.preferredColorScheme(.dark)
}
// nested OTHER VIEW providing the one value for binding makes the trick
private struct OtherView : View {
@State var providedValue : Bool = false
var body: some View {
BoolButtonView(boolValue: $providedValue)
}
}
}
Upvotes: 42
Reputation: 1233
Other way
struct AddContainer_Previews: PreviewProvider {
static var previews: some View {
AddContainer(isShowingAddContainer: .constant(false))
}
}
Upvotes: 30
Reputation: 3438
Just create a local static var, mark it as @State and pass it as a Binding $
struct AddContainer_Previews: PreviewProvider {
@State static var isShowing = false
static var previews: some View {
AddContainer(isShowingAddContainer: $isShowing)
}
}
Upvotes: 103