繁体   English   中英

SwiftUI,如何将 EnvironmnetObject Int 属性绑定到 TextField?

[英]SwiftUI, how to bind EnvironmnetObject Int property to TextField?

我有一个 ObservableObject,它应该保存我的应用程序 state:

final class Store: ObservableObject {
  @Published var fetchInterval = 30
}

现在,object 被注入到我的层次结构的根部,然后在树下的某个组件中,我试图访问它并将其绑定到 TextField,即:

struct ConfigurationView: View {
  @EnvironmnetObject var store: Store

  var body: some View {
    TextField("Fetch interval", $store.fetchInterval, formatter: NumberFormatter())
    Text("\(store.fetchInterval)"
  }
}
  1. 即使变量已绑定(使用$ ),属性也没有更新,初始值显示正确但是当我更改它时,文本字段会更改但绑定不会传播
  2. 与第一个问题相关的是,一旦值更改,我将如何接收事件,我尝试了以下代码段,但没有任何内容被触发(我假设是因为文本字段未正确绑定......
$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才能传播更改,这不是我想要的,我希望每次更改字段时都传播更改...

这样做,您甚至不必按 Enter。 如果将 Store() 放在 SceneDelegate 中,这也适用于 EnvironmentObject:

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: $0) {
                           self.store.fetchInterval = value.intValue
                       }}))
               Text("\(store.fetchInterval)").padding()
           }
     }
}

对于任何感兴趣的人,这是我最终得到的解决方案:

TextField("Seconds", text: Binding(
                    get: { String(self.store.fetchInterval) },
                    set: { self.store.fetchInterval = Int($0.filter { "0123456789".contains($0) }) ?? self.store.fetchInterval }
                ))

添加无效字符时会有一点延迟,但这是最干净的解决方案,它不允许无效字符而无需重置 TextField 的 state。

它还可以立即提交更改,而无需等待用户按 Enter 或无需等待字段模糊。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM