我觉得我缺少一些非常基本的东西,但是此示例SwiftUI代码在单击按钮时不会修改视图(尽管进行了绑定更新)
Tutorials我读过建议这是使用绑定的正确方法,并且视图应自动刷新
// Add observer
webView.addObserver(self, forKeyPath: "URL", options: .new, context: nil)
// Observe value
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if let key = change?[NSKeyValueChangeKey.newKey] {
print("observeValue \(key)") // url value
}
}
答案 0 :(得分:2)
您没有误解任何东西。当基础@State更改时,使用@Binding的View将更新,但是 @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()
}
}
答案 1 :(得分:1)
在SwiftUI的最高级别中,除非手动添加@state或其他刷新触发器,否则@Binding无法刷新View层次结构。
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}))
}
}
答案 2 :(得分:1)
SwiftUI视图会影响@Binding。 @State影响SwiftUI视图。 @State var影响视图,但是要影响另一个@State,必须通过在值名称中添加前导$来将其用作绑定,并且只能在SwiftUI中使用。
要从外部触发SwiftUI更改,即传递/更新Image,请使用如下所示的Publisher:
// 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"))
答案 3 :(得分:0)
您需要使用@State而不是@Binding。
如果UI应该在其值更改时更新,则可以将变量指定为 @State变量。这是真理的源头。
当视图不拥有此数据且它不是真相的来源时,请使用@Binding而不是@State。
这是您的变量:
@State var isSelected: Bool
答案 4 :(得分:0)
我有一个类似的问题,我创建了一个带有清除按钮和onChange属性的自定义文本字段(因为我们需要支持iOS 13,所以无法使用内置的)。
基本上,我使用带有getter / setter的绑定来触发onChange。由于某种原因,该按钮不会触发绑定的设置器。但是通常可以输入文字。
有人知道为什么会这样吗?
struct ParentView: View {
@State var text: String = ""
var body: some View {
CustomTextField(text: $text) { text in
print("\(text)")
}
}
}
struct CustomTextField: View {
@Binding var text: String
var onChange: ((String) -> Void)?
var body: some View {
HStack {
// entering text normally into this text field does trigger the binding setter below
TextField(
placeholder: "Enter Text...",
text: Binding(
get: {text},
set{
text = $0
onChange?($0)
}
)
)
Button {
text = "" // This does not trigger the above binding setter (so my onChange does not get called), but it does clear the text field as expected...
} label: {
Image(systemName: "xmark.circle.fill")
}
}
}
}
答案 5 :(得分:-1)
进一步研究一下,我想我了解发生了什么事。
在这种情况下,我想在构建自定义控件时使用@Binding
(例如SwiftUI的本机Toggle
,它也绑定到Bool
)
问题在于,ContentView_Previews
中的静态状态(即行@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())
}
}
@State static var
中的更改似乎不会触发预览重新渲染。在上面的代码中,我的@Binding
示例被移到MyButton
中,内容视图的虚拟环境实例被绑定到其isSelected
属性。轻按该按钮即可在SwiftUI预览中按预期更新视图。