SwiftUI@Binding update不支持';刷新视图
我觉得我缺少了一些非常基本的东西,但是这个示例SwiftUI代码在单击按钮时不会修改视图(尽管绑定更新) 我已经阅读了一些文章,认为这是使用绑定的正确方法,视图应该自动刷新SwiftUI@Binding update不支持';刷新视图,binding,swiftui,Binding,Swiftui,我觉得我缺少了一些非常基本的东西,但是这个示例SwiftUI代码在单击按钮时不会修改视图(尽管绑定更新) 我已经阅读了一些文章,认为这是使用绑定的正确方法,视图应该自动刷新 import SwiftUI struct ContentView: View { @Binding var isSelected: Bool var body: some View { Button(action: { self.isSelected.toggle
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)
}
}
您需要使用@State而不是@Binding
- 如果UI应在其值更改时更新,则将变量指定为 @状态变量。这是真理的源泉
- 当视图不拥有这些数据并且不是事实的来源时,可以使用@Binding而不是@State
@State var isSelected: Bool
再仔细研究一下,我想我明白发生了什么 在本例中,我希望在构建自定义控件时使用
@Binding
(比如SwiftUI的原生切换
,它也绑定到Bool
)
问题是ContentView\u Previews
中的静态(即@state static var selected:Bool=false
)不会在状态更改时触发预览的重新呈现,因此即使所选状态由于与控件的交互而更改,控件也会(ContentView\u Previews
的子级)不会重新呈现自身
这使得在SwiftUI预览中单独测试控件变得很困难,但是将状态移动到虚拟observeObject
实例中会正确运行。下面是代码:
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())
}
}
@State static var
中的更改似乎不会触发预览重新渲染。在上面的代码中,我的@Binding
示例被移动到MyButton
中,内容视图的虚拟环境实例被绑定到其isSelected
属性。点击按钮会按照SwiftUI p中的预期更新视图查看。在SwiftUI的顶层,@Binding无法刷新视图层次结构,除非手动添加@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}))
}
}
struct ContentView:View{
@绑定变量:Bool
@状态变量hiddenTrigger=false
var body:一些观点{
VStack{
文本(“\(hiddenTrigger?”:”))
按钮(操作:{
self.isSelected.toggle()
self.hiddenTrigger=self.isSelected
}) {
文本(self.isSelected?“Selected”:“not Selected”)
}
}
}
}
结构内容视图\u预览:PreviewProvider{
选择的静态变量:Bool=false
静态var预览:一些视图{
ContentView(isSelected:Binding(get:{selected},set:{newValue in
选定值=新值})
}
}
SwiftUI视图影响@Binding
@State
影响SwiftUI视图。
@State
var会影响视图,但若要影响另一个@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"))
//在Swift中声明发布者(在SwiftUI之外)。
public let imagePublisher=PassthroughSubject()
//它必须在SwiftUI中处理。
结构ContentView:View{
//声明更新视图的@State。
@状态变量图像:图像=图像(系统名称:“照片”)
var body:一些观点{
//使用@State图像声明
//并将此值订阅给publisher“imagePublisher”。
onReceive(imagePublisher,在中执行:{(输出:image))
self.image=output//每当publisher发送新值时,都会替换旧值
})
}
}
//以下是如何从Swift向更新SwiftUI发送值:
发送(图像(系统名:“照片”))
您没有误解任何内容。使用@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()
}
}
不确定,但请尝试此操作$isSelected.WrappedValue谢谢您的解释。
切换
之类的操作是如何工作的,它接受绑定
-切换是否无法设置绑定的值
?我的目标是构建一个可以操纵外部绑定值的控件。谢谢,这就是行为viour我误解了。我没有意识到绑定到全局变量(通过自定义get/set闭包)或者绑定到静态@State
不会刷新视图层次结构您的代码正是我要查找的。我不知道如何让@State
属性订阅发布者。谢谢:d使预览工作的关键是将属性从PreviewProvider推到包装器视图(在您的示例中为ContentView)。完成此操作后,@State
连接到@Binding
的效果与@EnvironmentObject
转换一样好。至少Xcode 12(beta 3)就是这种情况。Ragnarius感谢您的回答。但您是否也可以给出一个示例,说明如何使用您提到的其他方法,即“否则您可以绑定到发布者”我需要另一种方式来处理视图,其中视图在其初始值设定项中接受绑定,如切换。谢谢:)