SwiftUI @Binding Initialize
Asked Answered
P

7

100

Been playing around with SwiftUI and understood the concept of BindableObjects etc so far (at least I hope I do).

I bumped into a stupid problem I can't seem to find an answer for: How do you initialize a @Binding variable?

I have the following code:

struct LoggedInView : View {

    @Binding var dismissView: Bool

    var body: some View {
        VStack {
            Text("Hello World")
        }
    }
}

In my preview code, I want to pass that parameter of type Binding<Bool>:

#if DEBUG
struct LoggedInView_Previews : PreviewProvider {
    static var previews: some View {
        LoggedInView(dismissView: **Binding<Bool>**)
    }
}
#endif

How would I go an initialize it? tried:

Binding<Bool>.init(false)
Binding<Bool>(false)

Or even:

@Binding var dismissView: Bool = false

But none worked... any ideas?

Prepositor answered 20/6, 2019 at 12:25 Comment(0)
W
213

When you use your LoggedInView in your app you do need to provide some binding, such as an @State from a previous view or an @EnvironmentObject.

For the special case of the PreviewProvider where you just need a fixed value you can use .constant(false)

E.g.

#if DEBUG
struct LoggedInView_Previews : PreviewProvider {
    static var previews: some View {
        LoggedInView(dismissView: .constant(false))
    }
}
#endif
Worms answered 20/6, 2019 at 13:5 Comment(4)
That looks elegant. I just wonder if it makes the property immutable for the live preview.Canzone
It is, but that is typically all you need for the previewWorms
For a static preview, using immutable Binding.constant is fine, but it is totally unusable for a Live Preview where I wanna play around with just one view and see the value changed.Disobey
The solution of @Disobey below is better, because it lets you interact with the canvas.Loreeloreen
D
83

Using Binding.constant(false) is fine but only for static previews. If you actually wanna launch a Live Preview, constant will not behave the same way as the real case as it will never be updated by your actions. I personally use Live Preview a lot, as I can play around with an isolated view.

Here is what I do for previews requiring Binding:

import SwiftUI

struct SomeView: View {
   @Binding var code: String

   var body: some View {
     // some views modifying code binding
   }
}

struct SomeView_Previews: PreviewProvider {
  static var previews: some View {
    PreviewWrapper()
  }

  struct PreviewWrapper: View {
    @State(initialValue: "") var code: String

    var body: some View {
      SomeView(code: $code)
    }
  }
}
Disobey answered 7/1, 2020 at 10:6 Comment(3)
This works. But I'm wondering why adding a property like @State static var code: String = "" isn't enough?Serrulate
It isn't enough as it doesn't work, unlike the proposed solution. With static var the property value just doesn't get updated and it works the same way as using Binding.constant - which is fine for a static preview only.Disobey
NeverwinterMoon I've used this in my code and it works like a charm (I needed a @State since I had a Binding<> call). Gave answer +1Jonathonjonati
G
12
  • If you need a simple property that belongs to a single view you should use @State
  • If you need to have complex property that may belong to several view(like 2-3 views) you shall use @ObjectBinding
  • Lastly, if you need to have property that needs to use all around views you shall use @EnvironmentObject. Source for detail information

For your case, if you still would like to initialize your Binding variable you can use:

var binding: Binding = .constant(false)
Gallimaufry answered 20/6, 2019 at 12:58 Comment(1)
Note that since Xcode 11.3 Beta 5, (AT)ObjectBinding is now called (AT)ObservedObject (where (AT) = @)Shillong
M
1

In preview you have to use .constant(Bool(false)):

#if DEBUG
struct LoggedInView_Previews : PreviewProvider {
    static var previews: some View {
        LoggedInView(dismissView: .constant(Bool(false))
    }
}
#endif
Milan answered 22/1, 2022 at 13:38 Comment(1)
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.Cuprous
F
0

I'm using different configurations of my view within one preview (I'm working on a custom control and want to see a different configuration of it). I've extended the implementation provided by @NeverwinterMoon in order to create multiple independent instances of a view.

struct SomeView: View {
   @Binding var value: Int

   var body: some View {
     // some views modifying code binding
   }
}

struct SomeView_Previews: PreviewProvider {
  static var previews: some View {
    VStack {
      // The same view but with different configurations

      // Configuration #1
      PreviewWrapper() { value in
        SomeView(value: value)
          .background(Color.blue)
      }

      // Configuration #2      
      PreviewWrapper(initialValue: 2) { value in
        SomeView(value: value)
          .padding()
      }
    }
  }

  struct PreviewWrapper<Content: View>: View {
    @State var value: Int
    private let content: (Binding<Int>) -> Content
    
    init(
      initialValue: Int = 0,
      @ViewBuilder content: @escaping (Binding<Int>) -> Content
    ) {
      self.value = initialValue
      self.content = content
    }
    
    var body: some View {
      content($value)
    }
  }
}
Flatwise answered 22/9, 2021 at 9:25 Comment(0)
Q
0

if you have an object like viewModel you can also use .constant()

struct View_Previews: PreviewProvider {
  static var previews: some View {
     View(vm:.constant(ViewModel(text: "Sample Text")))
  }
}
Quality answered 9/6, 2022 at 13:29 Comment(0)
P
0

Without static and dynamic.

struct MyView: View {
    
    @Binding var date: Date
    
    var body: some View {
        DatePicker("Select date", selection: $date)
    }
}

#Preview {
    @State var previewDate: Date = Date()
    return MyView(date: $previewDate)
}
Purcell answered 24/4 at 15:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.