【问题标题】:SwiftUI search list from JSON fileJSON 文件中的 SwiftUI 搜索列表
【发布时间】: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”?谢谢你的建议。

【问题讨论】:

    标签: json swift search swiftui


    【解决方案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)
          }
        }
      }
    }
    

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

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

    我希望这会有所帮助:)

    【讨论】:

    • 非常感谢!我不知道如何编写您创建的var found,我所需要的只是实现您的代码并替换if cabinet.number == searchString 以及person.name 的条件if cabinet.number.localizedStandardContains(searchString),使其更像“全文搜索”,例如,因为我希望搜索列出所有可能的匹配项,而不仅仅是搜索时正确键入的那个。然后它就像一个魅力,再次感谢你!
    猜你喜欢
    • 1970-01-01
    • 2019-10-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-10
    • 1970-01-01
    • 2016-08-05
    相关资源
    最近更新 更多