您如何让 TextField 值更改触发对 SwiftUI 中另一条数据的更新?
How do you have a TextField value change trigger an update to another piece of data in SwiftUI?
我正在尝试学习 Swift、SwiftUI 和 Combine,总体上是 iOS 的新手。最后我想要一个列表,您可以搜索、过滤和排序。
到目前为止,当我在 TextField 中使用 onEditingChanged
时,过滤工作正常,但这需要按回车键。我只是不知道如何在 TextField filterText
更改时触发 activePeople
进行更新,以便 activePeople
列表在您键入 时进行过滤。
当我在视图中的 ForEach 中过滤列表时,我已经得到了一个可以工作的版本(请参阅注释掉的代码),但最终过滤和排序会变得更加复杂,拥有它似乎更有意义在那个视图之外。如果出于某种原因这不是正确的方法,请告诉我。
目前的代码如下:
import Combine
import SwiftUI
class Model: ObservableObject {
@Published var filterText: String = “”
@Published var activePeople: [Person] = []
private var allPeople : [Person] = [
Person( id: 1000, name: “Alexa” ),
Person( id: 1001, name: “Anaïs” ),
Person( id: 1002, name: “Earl” ),
Person( id: 1003, name: “Elba” ),
Person( id: 1004, name: "Emil” ),
Person( id: 1005, name: “Janeth” ),
Person( id: 1006, name: “Joselyn” ),
Person( id: 1007, name: “Lupita” ),
Person( id: 1008, name: “Mellie” ),
Person( id: 1009, name: “Vanita” ),
]
init() {
activePeople = allPeople
}
func filterList() {
if ( filterText == “” ) {
activePeople = allPeople
} else {
activePeople = allPeople.filter( { [=10=].name.localizedStandardContains( filterText ) } )
}
}
}
struct Person: Identifiable {
var id: Int
var name: String
}
import SwiftUI
struct ContentView: View {
@EnvironmentObject private var model: Model
var body: some View {
VStack {
Form {
Section {
TextField(“Filter Text”, text: $model.filterText, onEditingChanged: {_ in self.model.filterList()}
)
}
Section {
Text( "Filtered by: \(model.filterText)” )
ForEach( model.activePeople ) { person in
// if ( self.model.filterText == “” || person.name.localizedStandardContains( self.model.filterText )) {
Text( person.name )
// }
}
}
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
.environmentObject(Model())
}
}
只需在您的 ContentView 中应用过滤:
ForEach(model.activePeople.filter({ self.model.filterText.isEmpty ||
[=10=].name.localizedStandardContains(self.model.filterText)})) { person in
Text( person.name )
}
为了观察文本框输入的变化,可以观察模型中的变量。从视图中删除过滤逻辑可能也是一个好主意。
这方面的一个例子是在模型初始化时开始观察 filterText
。另外,请记住保留对从 sink
返回的可取消项的引用。
我们在这里所做的是每次 filterText
的值发生变化(由于文本字段绑定而发生变化),我们将过滤数组并将值分配给 activePeople
变量
var filterCancellable: AnyCancellable?
init() {
filterCancellable = $filterText.sink {[weak self] currentText in
guard let strongSelf = self else { return }
strongSelf.activePeople = strongSelf.filterList(with: currentText)
}
}
func filterList(with text: String) -> [Person] {
if ( text == "" ) {
return allPeople
} else {
return allPeople.filter( { [=10=].name.localizedStandardContains( text ) } )
}
}
这样你以后就可以
var body: some View {
VStack {
Form {
Section {
TextField("Filter Text", text: $model.filterText)
}
Section {
Text( "Filtered by: \(model.filterText)" )
ForEach( model.activePeople ) { person in
Text( person.name )
}
}
}
}
}
我正在尝试学习 Swift、SwiftUI 和 Combine,总体上是 iOS 的新手。最后我想要一个列表,您可以搜索、过滤和排序。
到目前为止,当我在 TextField 中使用 onEditingChanged
时,过滤工作正常,但这需要按回车键。我只是不知道如何在 TextField filterText
更改时触发 activePeople
进行更新,以便 activePeople
列表在您键入 时进行过滤。
当我在视图中的 ForEach 中过滤列表时,我已经得到了一个可以工作的版本(请参阅注释掉的代码),但最终过滤和排序会变得更加复杂,拥有它似乎更有意义在那个视图之外。如果出于某种原因这不是正确的方法,请告诉我。
目前的代码如下:
import Combine
import SwiftUI
class Model: ObservableObject {
@Published var filterText: String = “”
@Published var activePeople: [Person] = []
private var allPeople : [Person] = [
Person( id: 1000, name: “Alexa” ),
Person( id: 1001, name: “Anaïs” ),
Person( id: 1002, name: “Earl” ),
Person( id: 1003, name: “Elba” ),
Person( id: 1004, name: "Emil” ),
Person( id: 1005, name: “Janeth” ),
Person( id: 1006, name: “Joselyn” ),
Person( id: 1007, name: “Lupita” ),
Person( id: 1008, name: “Mellie” ),
Person( id: 1009, name: “Vanita” ),
]
init() {
activePeople = allPeople
}
func filterList() {
if ( filterText == “” ) {
activePeople = allPeople
} else {
activePeople = allPeople.filter( { [=10=].name.localizedStandardContains( filterText ) } )
}
}
}
struct Person: Identifiable {
var id: Int
var name: String
}
import SwiftUI
struct ContentView: View {
@EnvironmentObject private var model: Model
var body: some View {
VStack {
Form {
Section {
TextField(“Filter Text”, text: $model.filterText, onEditingChanged: {_ in self.model.filterList()}
)
}
Section {
Text( "Filtered by: \(model.filterText)” )
ForEach( model.activePeople ) { person in
// if ( self.model.filterText == “” || person.name.localizedStandardContains( self.model.filterText )) {
Text( person.name )
// }
}
}
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
.environmentObject(Model())
}
}
只需在您的 ContentView 中应用过滤:
ForEach(model.activePeople.filter({ self.model.filterText.isEmpty ||
[=10=].name.localizedStandardContains(self.model.filterText)})) { person in
Text( person.name )
}
为了观察文本框输入的变化,可以观察模型中的变量。从视图中删除过滤逻辑可能也是一个好主意。
这方面的一个例子是在模型初始化时开始观察 filterText
。另外,请记住保留对从 sink
返回的可取消项的引用。
我们在这里所做的是每次 filterText
的值发生变化(由于文本字段绑定而发生变化),我们将过滤数组并将值分配给 activePeople
变量
var filterCancellable: AnyCancellable?
init() {
filterCancellable = $filterText.sink {[weak self] currentText in
guard let strongSelf = self else { return }
strongSelf.activePeople = strongSelf.filterList(with: currentText)
}
}
func filterList(with text: String) -> [Person] {
if ( text == "" ) {
return allPeople
} else {
return allPeople.filter( { [=10=].name.localizedStandardContains( text ) } )
}
}
这样你以后就可以
var body: some View {
VStack {
Form {
Section {
TextField("Filter Text", text: $model.filterText)
}
Section {
Text( "Filtered by: \(model.filterText)" )
ForEach( model.activePeople ) { person in
Text( person.name )
}
}
}
}
}