SwiftUI,如何将 EnvironmnetObject Int 属性 绑定到 TextField?
SwiftUI, how to bind EnvironmnetObject Int property to TextField?
我有一个应该保存我的应用程序状态的 ObservableObject:
final class Store: ObservableObject {
@Published var fetchInterval = 30
}
现在,该对象被注入到我的层次结构的根部,然后在树下的某个组件中我试图访问它并将其绑定到 TextField,即:
struct ConfigurationView: View {
@EnvironmnetObject var store: Store
var body: some View {
TextField("Fetch interval", $store.fetchInterval, formatter: NumberFormatter())
Text("\(store.fetchInterval)"
}
}
- 即使变量已绑定(使用
$
),属性 未更新,初始值显示正确但当我更改它时,文本字段更改但绑定是未传播
- 与第一个问题相关的是,值更改后我将如何接收事件,我尝试了以下代码片段,但没有触发任何内容(我假设是因为文本字段未正确绑定...
$fetchInterval
.debounce(for: 0.8, scheduler: RunLoop.main)
.removeDuplicates()
.sink { interval in
print("sink from my code \(interval)")
}
非常感谢任何帮助。
编辑:我刚刚发现对于文本变量,绑定开箱即用,例如:
// on store
@Published var testString = "ropo"
// on component
TextField("Ropo", text: $store.testString)
Text("\(store.testString)")
只是在int字段上没有正确更新变量
编辑 2:
好的,我刚刚发现仅更改字段是不够的,必须按 Enter
才能传播更改,这不是我想要的,我希望每次更改字段时传播更改.. .
像这样操作,您甚至不必按回车键。这也适用于 EnvironmentObject,如果您将 Store() 放在 SceneDelegate 中:
struct ContentView: View {
@ObservedObject var store = Store()
var body: some View {
VStack {
TextField("Fetch interval", text: $store.fetchInterval)
Text("\(store.fetchInterval)")
}
} }
关于您的第二个问题:在 SwiftUI 中,如果其中的变量发生变化,视图总是会自动更新。
一个同样适用于 macos
的简单解决方案如何,如下所示:
import SwiftUI
final class Store: ObservableObject {
@Published var fetchInterval: Int = 30
}
struct ContentView: View {
@ObservedObject var store = Store()
var body: some View {
VStack{
TextField("Fetch interval", text: Binding<String>(
get: { String(format: "%d", self.store.fetchInterval) },
set: {
if let value = NumberFormatter().number(from: [=10=]) {
self.store.fetchInterval = value.intValue
}}))
Text("\(store.fetchInterval)").padding()
}
}
}
对于任何感兴趣的人,这是我最终得到的解决方案:
TextField("Seconds", text: Binding(
get: { String(self.store.fetchInterval) },
set: { self.store.fetchInterval = Int([=10=].filter { "0123456789".contains([=10=]) }) ?? self.store.fetchInterval }
))
添加无效字符时会有一小段延迟,但这是最简洁的解决方案,无需重置 TextField 的状态即可不允许无效字符。
它还会立即提交更改,而无需等待用户按下回车键或无需等待字段模糊。
我有一个应该保存我的应用程序状态的 ObservableObject:
final class Store: ObservableObject {
@Published var fetchInterval = 30
}
现在,该对象被注入到我的层次结构的根部,然后在树下的某个组件中我试图访问它并将其绑定到 TextField,即:
struct ConfigurationView: View {
@EnvironmnetObject var store: Store
var body: some View {
TextField("Fetch interval", $store.fetchInterval, formatter: NumberFormatter())
Text("\(store.fetchInterval)"
}
}
- 即使变量已绑定(使用
$
),属性 未更新,初始值显示正确但当我更改它时,文本字段更改但绑定是未传播 - 与第一个问题相关的是,值更改后我将如何接收事件,我尝试了以下代码片段,但没有触发任何内容(我假设是因为文本字段未正确绑定...
$fetchInterval
.debounce(for: 0.8, scheduler: RunLoop.main)
.removeDuplicates()
.sink { interval in
print("sink from my code \(interval)")
}
非常感谢任何帮助。
编辑:我刚刚发现对于文本变量,绑定开箱即用,例如:
// on store
@Published var testString = "ropo"
// on component
TextField("Ropo", text: $store.testString)
Text("\(store.testString)")
只是在int字段上没有正确更新变量
编辑 2:
好的,我刚刚发现仅更改字段是不够的,必须按 Enter
才能传播更改,这不是我想要的,我希望每次更改字段时传播更改.. .
像这样操作,您甚至不必按回车键。这也适用于 EnvironmentObject,如果您将 Store() 放在 SceneDelegate 中:
struct ContentView: View {
@ObservedObject var store = Store()
var body: some View {
VStack {
TextField("Fetch interval", text: $store.fetchInterval)
Text("\(store.fetchInterval)")
}
} }
关于您的第二个问题:在 SwiftUI 中,如果其中的变量发生变化,视图总是会自动更新。
一个同样适用于 macos
的简单解决方案如何,如下所示:
import SwiftUI
final class Store: ObservableObject {
@Published var fetchInterval: Int = 30
}
struct ContentView: View {
@ObservedObject var store = Store()
var body: some View {
VStack{
TextField("Fetch interval", text: Binding<String>(
get: { String(format: "%d", self.store.fetchInterval) },
set: {
if let value = NumberFormatter().number(from: [=10=]) {
self.store.fetchInterval = value.intValue
}}))
Text("\(store.fetchInterval)").padding()
}
}
}
对于任何感兴趣的人,这是我最终得到的解决方案:
TextField("Seconds", text: Binding(
get: { String(self.store.fetchInterval) },
set: { self.store.fetchInterval = Int([=10=].filter { "0123456789".contains([=10=]) }) ?? self.store.fetchInterval }
))
添加无效字符时会有一小段延迟,但这是最简洁的解决方案,无需重置 TextField 的状态即可不允许无效字符。
它还会立即提交更改,而无需等待用户按下回车键或无需等待字段模糊。