问题描述
我希望允许用户过滤长列表中的数据,以便更轻松地找到匹配的标题.
I want to allow the user to filter data in a long list to more easily find matching titles.
我在导航栏中放置了一个 TextView:
I have placed a TextView inside my navigation bar:
.navigationBarTitle(Text("Library"))
.navigationBarItems(trailing: TextField("search", text: $modelData.searchString)
我有一个响应搜索字符串变化的可观察对象:
I have an observable object which responds to changes in the search string:
class DataModel: ObservableObject {
@Published var modelData: [PDFSummary]
@Published var searchString = "" {
didSet {
if searchString == "" {
modelData = Realm.studyHallRealm.objects(PDFSummary.self).sorted(by: { $0.name < $1.name })
} else {
modelData = Realm.studyHallRealm.objects(PDFSummary.self).sorted(by: { $0.name < $1.name }).filter({ $0.name.lowercased().contains(searchString.lowercased()) })
}
}
}
一切正常,除了我必须在输入每个字母后点击字段.出于某种原因,在输入每个字母后焦点会从字段上移开(除非我点击建议的自动更正 - 整个字符串立即正确添加到字符串中)
Everything works fine, except I have to tap on the field after entering each letter. For some reason the focus is taken away from the field after each letter is entered (unless I tap on a suggested autocorrect - the whole string is correctly added to the string at once)
推荐答案
问题在于完全重建 NavigationView
导致文本字段焦点丢失.
The problem is in rebuilt NavigationView
completely that result in dropped text field focus.
这是工作方法.使用 Xcode 11.4/iOS 13.4 测试
Here is working approach. Tested with Xcode 11.4 / iOS 13.4
这个想法是为了避免基于 SwiftUI 引擎更新仅修改视图的知识重建 NavigationView
,因此使用分解我们在本地进行修改并仅在子视图之间直接传输所需值不影响顶部 NavigationView
,因此最后保持不变.
The idea is to avoid rebuild NavigationView
based on knowledge that SwiftUI engine updates only modified views, so using decomposition we make modifications local and transfer desired values only between subviews directly not affecting top NavigationView
, as a result the last kept stand.
class QueryModel: ObservableObject {
@Published var query: String = ""
}
struct ContentView: View {
// No QueryModel environment object here -
// implicitly passed down. !!! MUST !!!
var body: some View {
NavigationView {
ResultsView()
.navigationBarTitle(Text("Library"))
.navigationBarItems(trailing: SearchItem())
}
}
}
struct ResultsView: View {
@EnvironmentObject var qm: QueryModel // << injected here from top
var body: some View {
VStack {
Text("Search: \(qm.query)") // receive query string
}
}
}
struct SearchItem: View {
@EnvironmentObject var qm: QueryModel // << injected here from top
@State private var query = "" // updates only local view
var body: some View {
let text = Binding(get: { self.query }, set: {
self.query = $0; self.qm.query = $0; // transfer query string
})
return TextField("search", text: text)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView().environmentObject(QueryModel())
}
}
这篇关于为什么导航栏中的 SwiftUI TextField 一次只接受输入一个字符的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!