SwiftUI @Binding update doesn't refresh view
SwiftUI View affects @Binding
. @State
affects SwiftUI View.
@State
var affects the view, but to affect another @State
it must be used as binding by adding leading $
to value name and it works only inside SwiftUI.
To trigger SwiftUI change from outside, i.e. to deliver/update Image, use Publisher that looks like this:
// Declare publisher in Swift (outside SwiftUI)
public let imagePublisher = PassthroughSubject<Image, Never>()
// And within SwiftUI it must be handled:
struct ContentView: View {
// declare @State that updates View:
@State var image: Image = Image(systemName: "photo")
var body: some View {
// Use @State image declaration
image
// Subscribe this value to publisher "imagePublisher"
.onReceive(imagePublisher, perform: { (output: Image) in
// Whenever publisher sends new value, old one to be replaced
self.image = output
})
}
}
// And this is how to send value to update SwiftUI from Swift:
imagePublisher.send(Image(systemName: "photo"))
You have not misunderstood anything. A View using a @Binding will update when the underlying @State change, but the @State must be defined within the view hierarchy. (Else you could bind to a publisher)
Below, I have changed the name of your ContentView to OriginalContentView and then I have defined the @State in the new ContentView that contains your original content view.
import SwiftUI
struct OriginalContentView: View {
@Binding var isSelected: Bool
var body: some View {
Button(action: {
self.isSelected.toggle()
}) {
Text(isSelected ? "Selected" : "Not Selected")
}
}
}
struct ContentView: View {
@State private var selected = false
var body: some View {
OriginalContentView(isSelected: $selected)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
In the top Level of SwiftUI, @Binding cannot refresh View hierarchy unless manually adding a @state or other refreshing triggers.
struct ContentView: View {
@Binding var isSelected : Bool
@State var hiddenTrigger = false
var body: some View {
VStack {
Text("\(hiddenTrigger ? "" : "")")
Button(action: {
self.isSelected.toggle()
self.hiddenTrigger = self.isSelected
}) {
Text(self.isSelected? "Selected" : "not Selected")
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var selected: Bool = false
static var previews: some View {
ContentView(isSelected: Binding<Bool>(get: {selected}, set: { newValue in
selected = newValue}))
}
}