【问题标题】:How do you have a TextField value change trigger an update to another piece of data in SwiftUI?如何让 TextField 值更改触发 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())
    }

}

【问题讨论】:

    标签: swiftui combine


    【解决方案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 的工作方式将所有这些逻辑保留在视图中?
      • 您可以将其移至负责过滤数据的单独结构中。
      猜你喜欢
      • 2020-08-06
      • 2022-11-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-13
      • 1970-01-01
      • 1970-01-01
      • 2021-09-17
      相关资源
      最近更新 更多