Ios 如何在SwiftUI中检测文本字段的实时更改?
我有一个简单的文本字段,它绑定到状态“location”,如下所示Ios 如何在SwiftUI中检测文本字段的实时更改?,ios,textfield,swiftui,Ios,Textfield,Swiftui,我有一个简单的文本字段,它绑定到状态“location”,如下所示 TextField("Search Location", text: $location) 每次此字段更改时,我都要调用一个函数,如下所示: TextField("Search Location", text: $location) { self.autocomplete(location) } 然而,这不起作用。我知道有回调,onEditingChanged-但是这似乎只有在聚焦字段时才会触发 如何在每次更新字段时调
TextField("Search Location", text: $location)
每次此字段更改时,我都要调用一个函数,如下所示:
TextField("Search Location", text: $location) {
self.autocomplete(location)
}
然而,这不起作用。我知道有回调,onEditingChanged-但是这似乎只有在聚焦字段时才会触发
如何在每次更新字段时调用此函数?您可以使用自定义闭包创建绑定,如下所示:
TextField("Search Location", text: $location) {
self.autocomplete(location)
}
struct ContentView:View{
@状态变量位置:String=“”
var body:一些观点{
let binding=binding(获取:{
自我定位
},集:{
self.location=$0
//在这里你想干什么就干什么
})
返回VStack{
文本(“当前位置:\(位置)”)
TextField(“搜索位置”,文本:绑定)
}
}
}
如果需要使用视图模型,另一种解决方案可以是:
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)
迅捷2.0
在iOS 14、macOS 11或任何其他包含SwiftUI 2.0的操作系统中,有一个名为.onChange
的新修饰符,用于检测给定状态的任何更改:
struct ContentView: View {
@State var location: String = ""
var body: some View {
TextField("Your Location", text: $location)
.onChange(of: location) {
print($0) // You can do anything due to the change here.
// self.autocomplete($0) // like this
}
}
}
迅捷1.0
对于较旧的iOS和其他SwiftUI 1.0平台,您可以使用onReceive
:
.onReceive(location.publisher) {
print($0)
}
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)
}
}
}
请注意它返回的是更改,而不是整个值。如果您需要与onChange
相同的行为,可以使用组合并遵循@pawello2222提供的答案。SwiftUI 1和2
在接收时使用onReceive
:
.onReceive(location.publisher) {
print($0)
}
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)
}
)
}
}
来源:Hi@superpuccio,如果要使用ViewModel,可以将代码放在didSet{…}中。无需:可取消/接收;;-)这是一个比公认的IMO更清晰的答案。如果您的body var中有多个绑定,它可能会很快变得混乱。它是否需要是一个可观察对象?@Zorayr是的,否则您将无法获得已发布属性的更新。@FrankCheng在视图重新绘制时不会重新创建可观察对象(即再次请求视图主体时)。当视图位于另一个视图主体内且该视图被重绘时,将重新创建视图主体(即再次请求其主体,在该主体中有包含观察对象的子视图,因此将使用其所有属性(包括观察对象)完全重新创建视图)。如果是这种情况,您应该从外部将观察到的对象注入视图中,或者,如果您可以使用iOS 14,请尝试新的StateObject,它正好用于此。Hi kontiki!只是关于您有趣的答案的一个问题(我从未想过以这种方式使用绑定
):我想知道为什么如果我在位置变量上附加一个didSet,那么didSet根本不会被调用。类似于@State-var-location:String=”“{didSet{//do Something}
我不明白为什么函数没有被调用。谢谢。location上的didSet从不触发,因为您通过绑定更改的是location.wrappedValue,而不是location。是的,这完全有道理。我弄糊涂了。像往常一样:谢谢:)从SwiftUI中的textFieldDidChange()进行调整的伟大解决方案谢谢!我得到一个函数,它声明了一个不透明的返回类型,但是在它的主体中没有返回语句,从中可以推断出一个基础类型。文本更改时,不会调用onEditingChanged,而是在编辑开始或停止时调用onEditingChanged。单击文本字段内部时调用一次,然后单击“完成”时调用下一次。它确实是这样工作的。如果您正在寻找每次击键时调用的内容,那么这不是它。但这是一个很好的解决方案,具体问题是文本何时更改,而不是编辑何时开始/停止。这个问题的答案不正确。哦,你是对的。有用,但不是他们要求的。这实际上是一个非常好,干净和聪明的方式做这件事!这真的有效吗?您不需要将(位置)存储在某个位置以订阅并接收其值吗?@Xaxxus它工作得非常好。“我鼓励你自己尝试一下。”pawello2222我最终需要为我的用例做一些不同的事情。我有一个文本字段,下面有一个错误标签。错误标签只需要显示是否存在错误。触发错误标签的验证需要在击键(300毫秒)时运行。所以我最后做的是为我的文本字段创建一个可观察的对象视图模型。使用text和errorText published属性和I.onRecieve(viewModel.text.debounce(300,runloop.main))的$text变量触发我的验证,并使用.debounce进行验证,效果非常好。