为啥导航栏中的 SwiftUI TextField 一次只接受输入一个字符

Posted

技术标签:

【中文标题】为啥导航栏中的 SwiftUI TextField 一次只接受输入一个字符【英文标题】:Why does a SwiftUI TextField inside a navigation bar only accept input one character at a time为什么导航栏中的 SwiftUI TextField 一次只接受输入一个字符 【发布时间】:2020-04-20 14:54:09 【问题描述】:

我想让用户过滤长列表中的数据,以便更轻松地找到匹配的标题。

我在导航栏中放置了一个 TextView:

.navigationBarTitle(Text("Library"))
.navigationBarItems(trailing: TextField("search", text: $modelData.searchString)

我有一个响应搜索字符串变化的可观察对象:

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()) )
                
            
        

一切正常,除了我必须在输入每个字母后点击该字段。出于某种原因,输入每个字母后焦点从字段中移开(除非我点击建议的自动更正 - 整个字符串一次正确添加到字符串中)

【问题讨论】:

【参考方案1】:

问题在于完全重建NavigationView,导致文本字段焦点下降。

这是工作方法。使用 Xcode 11.4 / ios 13.4 测试

我们的想法是避免重建 NavigationView 基于 SwiftUI 引擎更新修改过的视图的知识,因此使用分解我们在本地进行修改并仅在子视图之间直接传输所需的值而不影响顶部 @987654325 @,因此最后保留的立场。

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 一次只接受输入一个字符的主要内容,如果未能解决你的问题,请参考以下文章

自定义属性包装器无法准确反映我在 SwiftUI 中的 TextField 的状态,知道为啥吗?

从 SwiftUI 中的导航栏中删除后退按钮文本

SwiftUI:模式关闭后导航栏中的按钮不会触发

@State 错误我位于导航栏的 TextField - SwiftUI

在SwiftUI导航栏中嵌入视图作为标题。

为啥我的按钮位于导航栏中的“工作流程”下方?