JSON 文件中的 SwiftUI 搜索列表

Posted

技术标签:

【中文标题】JSON 文件中的 SwiftUI 搜索列表【英文标题】:SwiftUI search list from JSON file 【发布时间】:2020-04-08 12:23:46 【问题描述】:

目前我的SearchView 在数组names 上使用了一个简单的过滤器,我需要它来让它通过我的JSON 文件进行搜索。我有一个具有这种结构的 JSON 文件:

struct UcmData: Codable, Identifiable 
    let id: Int
    let building: [Building]


// MARK: - Building
struct Building: Codable, Identifiable 
    let id: Int
    let title, subtitle, info, image: String
    let floor: [Floor]


// MARK: - Floor
struct Floor: Codable, Identifiable 
    let id, number: Int
    let title, subtitle, image: String
    let cabinet: [Cabinet]?


// MARK: - Cabinet
struct Cabinet: Codable, Identifiable 
    let id: Int
    let number: String
    let person: [Person]


// MARK: - Person
struct Person: Codable, Identifiable 
    let id: Int
    let name: String

搜索视图:

struct SearchView: View 

    let names = ["306 B", "doc. Ing. Michal Čerňanský, PhD."]
    let ucmData = Bundle.main.decode(UcmData.self, from: "ucm_data.json")
    @State private var searchText = ""
    @State private var showCancelButton: Bool = false


    var body: some View 
        VStack 
            HStack 
                HStack 
                    Image(systemName: "magnifyingglass")
                    TextField("Zadajte text pre vyhľadávanie", text: $searchText, onEditingChanged:  isEditing in
                        self.showCancelButton = true
                    , onCommit: 
                        print("onCommit")
                    ).foregroundColor(.primary)
                    Button(action: 
                        self.searchText = ""
                    ) 
                        Image(systemName: "xmark.circle.fill").opacity(searchText == "" ? 0 : 1)
                    
                
                .padding(EdgeInsets(top: 8, leading: 6, bottom: 8, trailing: 6))
                .foregroundColor(.secondary)
                .background(Color(.secondarySystemBackground))
                .cornerRadius(10.0)
                if showCancelButton  
                    Button("Cancel") 
                            UIApplication.shared.endEditing(true)
                            self.searchText = ""
                            self.showCancelButton = false
                    
                    .foregroundColor(Color(.systemBlue))
                
            
            .padding(.horizontal)
            .navigationBarHidden(showCancelButton)
            List 
                ForEach(self.names.filter
                    self.searchText.isEmpty ? $0.localizedStandardContains("") :
                        $0.localizedStandardContains(self.searchText)
                , id: \.self)  name in
                    Text(name)
                
            
            .navigationBarTitle(Text("Vyhľadávanie"))
            .resignKeyboardOnDragGesture()
        
    


extension UIApplication 
    func endEditing(_ force: Bool) 
        self.windows
            .filter$0.isKeyWindow
            .first?
            .endEditing(force)
    


struct ResignKeyboardOnDragGesture: ViewModifier 
    var gesture = DragGesture().onChanged_ in
        UIApplication.shared.endEditing(true)
    
    func body(content: Content) -> some View 
        content.gesture(gesture)
    


extension View 
    func resignKeyboardOnDragGesture() -> some View 
        return modifier(ResignKeyboardOnDragGesture())
    


struct SearchView_Previews: PreviewProvider 
    static var previews: some View 
        Group 
           SearchView()
              .environment(\.colorScheme, .light)

           SearchView()
              .environment(\.colorScheme, .dark)
        
    

如何使searchTextCabinet.numberPerson.name 匹配,并在JSON 文件中列出匹配项目及其路径,例如“building.title > floor.title > cabinet.number”或对于人“building.title > floor.title > cabinet.number > person.name”?谢谢你的建议。

【问题讨论】:

【参考方案1】:

不完全确定,但我假设搜索字段可以包含人名或内阁编号,您希望根据这些名称过滤数据集并以时尚的方式显示列表:

building.title > floor.title > cabinet.number

building.title > floor.title > cabinet.number > person.name

也许这些方面的东西可能会有所帮助:

struct ContentView: View 
  let data: UcmData
  @State var searchString = ""

  var found: [String] 
    var result = [String]()
    data.building.forEach  (building) in //go through every building
      building.floor.forEach  (floor) in //go through every floor
        floor.cabinet?.forEach  (cabinet) in //go through every cabinet
          var cabinetFound: String 
            return "\(building.title) > \(floor.title) > \(cabinet.number)"
          

          if cabinet.number == searchString  //check with cabinet [!]
            result.append(cabinetFound) //add search result
           else 
            cabinet.person.forEach  (person) in //go through every person
              if person.name == searchString  //check with person [!]
                let personFound = cabinetFound + " > \(person.name)"
                result.append(personFound) //add search result
              
            
          
        
      
    
    return result
  

  var body: some View 
    VStack 
      TextField("search string", text: $searchString) //search field
      List(found, id: \.self)  (current) in //List of search results
        Text(current)
      
    
  

*此示例只是您视图的子集,仅展示搜索功能。如果有意义就整合它。

    foundStringArray,将在请求时计算 当搜索字段更新时,searchString 更新并重新渲染正文,这将使用 found 中的元素刷新 List

我希望这会有所帮助:)

【讨论】:

非常感谢!我不知道如何编写您创建的var found,我所需要的只是实现您的代码并替换if cabinet.number == searchString 以及person.name 的条件if cabinet.number.localizedStandardContains(searchString),使其更像“全文搜索”,例如,因为我希望搜索列出所有可能的匹配项,而不仅仅是搜索时正确键入的那个。然后它就像一个魅力,再次感谢你!

以上是关于JSON 文件中的 SwiftUI 搜索列表的主要内容,如果未能解决你的问题,请参考以下文章

自学IOS开发第3天·基础SwiftUI之动态滑动列表(上)

自学IOS开发第3天·基础SwiftUI之动态滑动列表(上)

如何将 csv 文件读入 SWI prolog 中的列表列表,其中内部列表代表 CSV 的每一行?

SwiftUI 中的动态列表从 JSON 和 Textfield 更新

SwiftUI:过滤的列表索引与新列表不对应

来自 JSON/Dictionary 的 SwiftUI 列表