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

Posted

技术标签:

【中文标题】SwiftUI,如何将 EnvironmnetObject Int 属性绑定到 TextField?【英文标题】:SwiftUI, how to bind EnvironmnetObject Int property to TextField? 【发布时间】:2020-04-19 17:54:33 【问题描述】:

我有一个 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)"
  

    即使绑定了变量(使用$),属性也没有更新,初始值显示正确,但是当我更改它时,文本字段更改但绑定没有传播 与第一个问题相关的是,一旦值更改,我将如何接收事件,我尝试了以下 sn-p,但没有任何内容被触发(我假设是因为文本字段未正确绑定...
$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 才能传播更改,这不是我想要的,我希望每次更改字段时都传播更改...

【问题讨论】:

【参考方案1】:

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

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

添加无效字符时会有一点延迟,但这是最干净的解决方案,不允许在不重置 TextField 状态的情况下添加无效字符。

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

【讨论】:

【参考方案2】:

这样做,您甚至不必按 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 中,如果视图中的变量发生更改,视图总是会自动更新。

【讨论】:

嗯,是的,只是使用文本直接改变观察值,但验证呢?它只会尝试将文本放在那里对吗? 如果您只在 iPhone 上使用您的应用程序,最简单的解决方案是在您的 TextField 下添加“.keyboardType(.numberPad)”。请注意,在模拟器上,您必须在单击 TextField 后打开小键盘 (CMD+K) 才能正确模拟此行为。如需更复杂的解决方案,请查看:***.com/questions/58733003/… 不,不幸的是(?)我正在开发一个 mac 应用程序,所以允许文本值更让人头疼 此代码无法编译。 TextField 将 Binding 作为参数。它不需要 Int。【参考方案3】:

如何在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()
           
     

【讨论】:

我确实最终选择了类似的东西,谢谢

以上是关于SwiftUI,如何将 EnvironmnetObject Int 属性绑定到 TextField?的主要内容,如果未能解决你的问题,请参考以下文章

如何将 swiftUI 按钮连接到 NSView 操作?

如何将 UISearchController 与 SwiftUI 集成

如何指定将保存 SwiftUI 自定义视图的数组的类型信息

SwiftUI - 如何将当前的强调色传递给工作表?

如何将字典项分别添加到 SwiftUI 列表中

如何将我的自定义 ButtonStyle 添加到 swiftui3 中的快捷方式 swiftui .buttonstyle() 属性