Sagar Kothari Turvo
Sagar Kothari Turvo

Reputation: 1033

SwiftUI preview provider with binding variables

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

Answers (5)

Mojtaba Hosseini
Mojtaba Hosseini

Reputation: 119292

From Xcode 16

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

Daniel Morell
Daniel Morell

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

LukeSideWalker
LukeSideWalker

Reputation: 7910

If you want to watch the binding:

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

Ernist Isabekov
Ernist Isabekov

Reputation: 1233

Other way

    struct AddContainer_Previews: PreviewProvider {
      static var previews: some View {
        AddContainer(isShowingAddContainer: .constant(false))
      }
    }

Upvotes: 30

nine stones
nine stones

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

Related Questions