如何让 TextField 值更改触发 SwiftUI 中另一条数据的更新?
Posted
技术标签:
【中文标题】如何让 TextField 值更改触发 SwiftUI 中另一条数据的更新?【英文标题】:How do you have a TextField value change trigger an update to another piece of data in SwiftUI? 【发布时间】:2019-10-10 22:31:11 【问题描述】:我正在尝试学习 Swift、SwiftUI 和 Combine,总的来说,我是 ios 新手。最终我想要一个可以搜索、过滤和排序的列表。
到目前为止,当我在 TextField 中使用 onEditingChanged
时,我的过滤工作正常,但这需要按 Enter。我只是不知道如何在 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( $0.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())
【问题讨论】:
【参考方案1】:为了观察文本字段输入的变化,您可以观察模型中的变量。从视图中删除过滤逻辑可能也是一个好主意。
这方面的一个例子是在模型初始化时开始观察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( $0.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 )
【讨论】:
【参考方案2】:只需在您的 ContentView 中应用过滤:
ForEach(model.activePeople.filter( self.model.filterText.isEmpty ||
$0.name.localizedStandardContains(self.model.filterText))) person in
Text( person.name )
【讨论】:
有没有办法让这个不被看到?最终我想使用多个过滤器并应用一个排序。是否按照 SwiftUI 的工作方式将所有这些逻辑保留在视图中? 您可以将其移至负责过滤数据的单独结构中。以上是关于如何让 TextField 值更改触发 SwiftUI 中另一条数据的更新?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Swift 中更改键盘完成按钮上 Textfield 的文本?
Swift inout 如何在未更改时不复制回属性,以不触发对象设置器
Swift 如何在另一个 UITextField 突出显示或具有值时禁用 TextField
我如何在SWIFTUI中把textField作为firstResponder,就像Swift一样:textField.becomesFirstResponder。