如何检测 SwiftUI 中 TextField 的实时变化?

How to detect live changes on TextField in SwiftUI?

我有一个像这样绑定到状态 'location' 的简单 TextField,

TextField("Search Location", text: $location)

每次这个字段改变时我想调用一个函数,像这样:

TextField("Search Location", text: $location) {
   self.autocomplete(location)
}

但是这不起作用。我知道有回调 onEditingChanged - 但这似乎只有在聚焦字段时才会触发。

如何让这个函数在每次更新字段时调用?

您可以使用自定义闭包创建绑定,如下所示:

struct ContentView: View {
    @State var location: String = ""

    var body: some View {
        let binding = Binding<String>(get: {
            self.location
        }, set: {
            self.location = [=10=]
            // do whatever you want here
        })

        return VStack {
            Text("Current location: \(location)")
            TextField("Search Location", text: binding)
        }

    }
}

另一种解决方案,如果您需要使用 ViewModel,可以是:

import SwiftUI
import Combine

class ViewModel: ObservableObject {
    @Published var location = "" {
        didSet {
            print("set")
            //do whatever you want
        }
    }
}

struct ContentView: View {
    @ObservedObject var viewModel = ViewModel()

    var body: some View {
        TextField("Search Location", text: $viewModel.location)
    }
}

我发现最有用的是 TextField 有一个名为 onEditingChanged 的​​ 属性,它在编辑开始和编辑完成时被调用。

TextField("Enter song title", text: self.$userData.songs[self.songIndex].name, onEditingChanged: { (changed) in
    if changed {
        print("text edit has begun")
    } else {
        print("committed the change")
        saveSongs(self.userData.songs)
    }
})
    .textFieldStyle(RoundedBorderTextFieldStyle())
    .font(.largeTitle)

SwiftUI 2.0

从 iOS 14、macOS 11 或任何其他 OS 包含 SwiftUI 2.0,有一个名为 .onChange 的新修饰符可以检测任何更改给定 state:

struct ContentView: View {
    @State var location: String = ""

    var body: some View {
        TextField("Your Location", text: $location)
            .onChange(of: location) {
                print([=10=]) // You can do anything due to the change here.
                // self.autocomplete([=10=]) // like this
            }
    }
}

SwiftUI 1.0

对于较旧的 iOS 和其他 SwiftUI 1.0 平台,您可以使用 onReceive:

.onReceive(location.publisher) { 
    print([=11=])
}
**请注意**它 returns **变化** 而不是整个值。如果您需要与 onChange 相同的行为,您可以使用 **combine** 并按照@pawello2222 提供的答案进行操作。

SwiftUI 1 & 2

使用onReceive:

import Combine
import SwiftUI

struct ContentView: View {
    @State var location: String = ""

    var body: some View {
        TextField("Search Location", text: $location)
            .onReceive(Just(location)) { location in
                // print(location)
            }
    }
}

虽然其他答案可能有用,但这个答案对我有用,我需要聆听文本变化并对其做出反应。

第一步创建一个扩展函数

extension Binding {
    func onChange(_ handler: @escaping (Value) -> Void) -> Binding<Value> {
        Binding(
            get: { self.wrappedValue },
            set: { newValue in
                self.wrappedValue = newValue
                handler(newValue)
            }
        )
    }
}

现在对 TextField 中的绑定调用 change,如下所示。

  TextField("hint", text: $text.onChange({ (value) in
      //do something here
  }))

来源:HackingWithSwift