首页 > 解决方案 > 优化列表搜索

问题描述

如何优化列表中的搜索。我有两千条记录。我不想通过 NSPredicate 进行搜索,因为我想在比较之前通过清理数字并减少字母的函数传递字段中的内容。您能否以某种方式延迟,使其不会立即搜索,而是在一段时间后或用户完成输入后搜索。我也听说过Combine之类的东西,但我不知道如何使用它。

歌集列表

import CoreData
import SwiftUI

struct SongbookView: View {
    @State var searchText: String = ""
    @Environment(\.managedObjectContext) var managedObjectContext
    @FetchRequest(
        entity: Song.entity(),
        sortDescriptors: [NSSortDescriptor(keyPath: \Song.number, ascending: true)]
    ) var songs: FetchedResults<Song>
    
    var body: some View {
        NavigationView{
            VStack{
                SearchBar(text: $searchText)
                Spacer()
                List(songs.filter({searchText.isEmpty ? true : removeNumber(str: $0.content!.lowercased()).contains(searchText.lowercased()) || String($0.number).contains(searchText)}), id:\.objectID) { song in
                    NavigationLink(destination: DetailView(song: song, isSelected: song.favorite)) {
                        HStack{
                            Text("\(String(song.number)). ") .font(.headline) + Text(song.title ?? "Brak tytułu")
                            if song.favorite {
                                Spacer()
                                Image(systemName: "heart.fill")
                                    .accessibility(label: Text("To jest ulubiona pieśń"))
                                    .foregroundColor(.red)
                            }
                        }.lineLimit(1)
                    }
                }.id(UUID())
                .listStyle(InsetListStyle())
                .animation(.default)
            }
            .padding(.top, 10)
            .navigationBarTitleDisplayMode(.inline)
            .toolbar {
                ToolbarItem(placement: .principal) {
                    Text("Śpiewnik")
                        .font(.system(size: 20))
                        .bold()
                }
            }
        }
    }
    
    func removeNumber(str: String) -> String {
        var result = str
        let vowels: Set<Character> = ["1", "2", "3", "4", "5", "6", "7", "8", "9"]
        result.removeAll(where: { vowels.contains($0) })
        return result
    }
}

搜索栏

import SwiftUI

struct SearchBar: View {
    @Binding var text: String

    @State var isEditing = false
        
    var body: some View {
        HStack {
            
            TextField("Szukaj ...", text: $text)
                .padding(7)
                .padding(.horizontal, 25)
                .background(Color(.systemGray6))
                .cornerRadius(8)
                .overlay(
                    HStack {
                        Image(systemName: "magnifyingglass")
                            .foregroundColor(.gray)
                            .frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)
                            .padding(.leading, 8)
                        
                        if isEditing {
                            Button(action: {
                                self.text = ""
                                
                            }) {
                                Image(systemName: "multiply.circle.fill")
                                    .foregroundColor(.gray)
                                    .padding(.trailing, 8)
                            }
                        }
                    }
                )
                .padding(.horizontal, 10)
                .onTapGesture {
                    self.isEditing = true
                }
            
            if isEditing {
                Button(action: {
                    self.isEditing = false
                    self.text = ""
                    UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
                }) {
                    Text("Anuluj")
                }
                .padding(.trailing, 10)
                .transition(.move(edge: .trailing))
                .animation(.default)
            }
        }
    }
}

标签: listsearchfilterswiftuicombine

解决方案


每当您更改您的文本SearchBar(即您键入的每个字符)时,SongbookView都会更新,因为您正在使用文本绑定。您想要的是仅在按回车键时进行一次更新。有很多方法可以做到这一点。执行此操作并保持绑定设置的一种快速方法是:

struct SearchBar: View {
    @Binding var text: String
    @State var txt: String = ""   // <--- here a temp var
    @State var isEditing = false
        
    var body: some View {
        HStack {
            TextField("Szukaj ...", text: $txt) // <--- here
                .onSubmit {
                    text = txt   // <--- here only update on return press
                }
                .padding(7)
                ....
               .onAppear {
                  txt = text   // <--- here if needed
               }
        

如果您使用的是 ios-14,请使用

        TextField("Szukaj ...", text: $txt, onCommit: {  // <--- here
            text = txt   // <--- here
        })

推荐阅读