Список поиска SwiftUI из файла JSON - PullRequest
1 голос
/ 08 апреля 2020

В настоящее время мой 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
}

SearchView:

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

Как мне сделать соответствие searchText с Cabinet.number или Person.name и списком соответствие элементов их пути в файле JSON, например, "building.title> floor.title> cab inet .number" или для персоны "building.title> floor.title> cab inet .number> person.name" ? Спасибо за предложения.

1 Ответ

1 голос
/ 08 апреля 2020

Не совсем уверен, но я предполагаю, что в поле поиска может быть либо имя человека, либо номер кабины inet, по которому вы хотите отфильтровать свой набор данных и показать список в моде:

building.title> floor.title> cab inet .number

или

building.title> floor.title> cab inet .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. found - это Array из String, который будет вычисляться по запросу
  2. При обновлении поля поиска, searchString обновляет и повторно отображает тело, которое будет обновлять sh List с элементами в found

Надеюсь, это поможет:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...