SwiftUI Фильтрация / Поиск двухуровневой модели данных - PullRequest
0 голосов
/ 30 марта 2020

Я пытаюсь использовать панель поиска для поиска / фильтрации через двухуровневую модель данных в SwiftUI:

struct CategorySection: Identifiable {
    var id = UUID()
    var title: String
    var image: String
    var color: Color
    var paintings: [Painting]
}

struct Painting {
    var title: String
    var size: String
    var year: String
    var text: String
    var show: Bool
} 

let categorySectionData: [CategorySection] = [
    CategorySection(title: "Flowers",
                    image: "Spring",
                    color: Color(#colorLiteral(red: 0.9098039269, green: 0.4784313738, blue: 0.6431372762, alpha: 1)),
                    paintings: [
                        Painting(title: "Spring", size: "70 x 60cm", year: "2001", text: "Spring", show: false),
                        Painting(title: "Flowers", size: "60 x 50cm", year: "2002", text: "The", show: false),
                        Painting(title: "Corn Poppys", size: "70 x 50cm", year: "2005", text: "Year", show: false),
        ]
    ),
    CategorySection(title: "Animals",
                    image: "Deers",
                    color: Color(#colorLiteral(red: 0.2745098174, green: 0.4862745106, blue: 0.1411764771, alpha: 1)),
                    paintings: [
                        Painting(title: "Tigers", size: "70 x 60cm", year: "2001", text: "Spring", show: false),
                        Painting(title: "Deers", size: "60 x 50cm", year: "2002", text: "The", show: false),
                        Painting(title: "Puppies", size: "70 x 50cm", year: "2005", text: "Year", show: false),
        ]
    )
]

Основная цель - фильтровать элементы, такие как title: "Spring" и * 1005. * в Painting структуре внутри CategorySection, отобразите совпавшие результаты в виде рисунков title с в списке и передайте данные через NavigationLink для следующего просмотра SearchDetail, чтобы отобразить, когда пользователь нажимает на один из них.

Я попытался выполнить следующие действия для поиска первых элементов, но Xcode только что выдал мне кучу ошибок.

let array = locationSectionData[0].paintings[0]
List {
   ForEach(array.filter {$0.hasPrefix(searchText) || searchText == ""}, id:\.self) { searchText in
       NavigationLink(destination: SearchDetail(item: searchText)) {
           Text(searchText)
       }
   }
}

Однако вышеприведенное решение работает для простых массивов, таких как:

let array = ["Spring", "Deer", "New Year", "Flowers"]

, но не для многоуровневых структур данных.

В идеале, результат поиска должен возвращать целые экземпляры структуры Painting, такие как

Painting(title: "Spring", size: "70 x 60cm", year: "2001", text: "Spring", show: false)

, а не только отдельные элементы, которые соответствуют, если какой-либо элемент внутри него соответствует входу панели поиска ,

Если у кого-то есть идеи, как я могу решить эту проблему, это было бы здорово! На данный момент, я даже не уверен, что это возможно, учитывая текущую структуру данных. Модификации структуры данных являются приемлемыми.

Спасибо!

Отредактировано: Мне удалось отобразить полный список названий картин без функции фильтра, благодаря помощи @ jtouzy

List {
    ForEach(categorySectionData) { section in
        Section(header: Text(section.title)) {
            ForEach(section.paintings.indices, id: \.self) { painting in
                ForEach(section.paintings[painting].title.filter {$0.contains(searchText) || searchText.isEmpty}, id:\.self) { searchText in
                    NavigationLink(destination: SearchDetail(painting: section.paintings[painting])) {
                                        Text(section.paintings[painting].title)
                    }
                }
            }
        }
    }
}

Однако Xcode сообщает об ошибке Value of type 'String.Element' (aka 'Character') has no member 'contains' в строке ForEach(section.paintings[painting].title.filter {$0.contains(searchText) || searchText.isEmpty}, id:\.self) { searchText in. Я знаю, что это, вероятно, потому что теперь это не массив.

1 Ответ

0 голосов
/ 30 марта 2020

Для вашего ответа ,

Ваша функция ForEach основана не на строке, а на объекте Painting.

Поэтому вы не можете использовать Функция hasPrefix() для элементов массива.

Вместо этого откройте свой элемент title в функции filter:

$0.title.hasPrefix(searchText)

Вам следует выполнить итерации по категориям и затем на ваших картинах, что-то вроде этого (не запускается):

List {
    ForEach(categorySectionData) { section in
        Section(header: Text(section.title)) {
            ForEach(section.paintings) { painting in // Here with your filter
               NavigationLink(destination: SearchDetail(item: painting)) {
                  Text(painting.title)
               }
            }
        }
    }
}

В других руках

Я предлагаю вам использовать contains(where:) вместо hasPrefix(), чтобы обеспечить возможность поиска по всем словам.

И чтобы быть более чистым в вашем коде, используйте searchText.isEmpty вместо searchText == "".

EDIT Отредактированный вопрос см. В моем ответе в комментариях ниже.

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