SwiftUI @Binding 更新不会刷新视图

sim*_*eon 16 binding swiftui

我觉得我缺少一些非常基本的东西,但是当单击按钮时,这个示例 SwiftUI 代码不会修改视图(尽管绑定更新)

我读过的教程表明这是使用绑定的正确方法,视图应该自动刷新

import SwiftUI

struct ContentView: View {
    @Binding var isSelected: Bool

    var body: some View {
        Button(action: {
            self.isSelected.toggle()
        }) {
            Text(isSelected ? "Selected" : "Not Selected")
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    @State static var selected: Bool = false

    static var previews: some View {
        ContentView(isSelected: $selected)
    }
}
Run Code Online (Sandbox Code Playgroud)

E.C*_*oms 12

在 SwiftUI 的顶层,@Binding 无法刷新 View 层次结构,除非手动添加 @state 或其他刷新触发器。

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}))
    }
}
Run Code Online (Sandbox Code Playgroud)


rag*_*ius 10

你没有误解任何东西。使用@Binding 的视图将在底层@State 更改时更新,但@State 必须在视图层次结构中定义。(否则你可以绑定到发布者)

下面,我将 ContentView 的名称更改为 OriginalContentView,然后在包含原始内容视图的新 ContentView 中定义了 @State。

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()
    }
}
Run Code Online (Sandbox Code Playgroud)


小智 7

SwiftUI 视图会影响@Binding. @State影响 SwiftUI 视图。 @Statevar 影响视图,但要影响另一个视图,@State它必须通过添加前导$值名称来用作绑定,并且它只能在 SwiftUI 中工作。

要从外部触发 SwiftUI 更改,即交付/更新图像,请使用如下所示的 Publisher:

// Declare publisher in Swift (outside SwiftUI).
public let imagePublisher = PassthroughSubject<Image, Never>()
    
// It must be handled within SwiftUI.
struct ContentView: View {
    // Declare a @State that updates View.
    @State var image: Image = Image(systemName: "photo")
    var body: some View {
        // Use @State image declaration
        // and subscribe this value to publisher "imagePublisher".
        image.onReceive(imagePublisher, perform: { (output: Image) in
            self.image = output  // Whenever publisher sends new value, old one to be replaced
        })
    }
}

// And this is how to send value to update SwiftUI from Swift:
imagePublisher.send(Image(systemName: "photo"))
Run Code Online (Sandbox Code Playgroud)


sim*_*eon 5

进一步研究这个问题,我想我明白发生了什么。

@Binding在这种情况下,我想在构建自定义控件时使用(例如 SwiftUI 的 native Toggle,它也绑定到 a Bool

问题是,当状态更改时ContentView_Previews,(即 line @State static var selected: Bool = false)中的静态状态不会触发预览的重新渲染,因此即使所选状态由于与控件交互而发生了更改,控件(ContentView_Previews) 不重新渲染自身

这使得在 SwiftUI 预览中单独测试控件变得很困难,但是将状态移动到虚拟ObservableObject实例中可以正常工作。这是代码:

import SwiftUI
import Combine

class SomeData: ObservableObject {
    @Published var isOn: Bool = false
}

struct MyButton: View {
    @Binding var isSelected: Bool

    var body: some View {
        Button(action: {
            self.isSelected.toggle()
        }) {
            Text(isSelected ? "Selected" : "Not Selected")
        }
    }
}

struct ContentView: View {
    @EnvironmentObject var data: SomeData

    var body: some View {
        MyButton(isSelected: $data.isOn)
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView().environmentObject(SomeData())
    }
}
Run Code Online (Sandbox Code Playgroud)

似乎更改@State static var不会触发预览重新渲染。在上面的代码中,我的@Binding示例被移入MyButton,内容视图的虚拟环境实例绑定到其isSelected属性。点击按钮会按照 SwiftUI 预览中的预期更新视图。