again maybe a beginner question. I've implemented a search function in my app. But I'm very unhappy with my code. I know I have to have to put my searchText into the .searchable() {...} But also with help from different tutorials my knowledge isn't good enough to do this. Could you please habe a look into my code and give me a hint so I could learn from your solution?
//
// FavoriteView.swift
// Blindzeln_Prototyp
//
// Created by Michael Ecke on 25.01.22.
//
import SwiftUI
struct FavoriteView: View {
@EnvironmentObject var blindzeln: BLINDzeln
@State private var searchText = ""
var body: some View {
NavigationView {
List{
ForEach(blindzeln.favorites, id: \.entryID) { item in
if searchText==""{
NavigationLink(destination: FavoriteDetailView(item: item)) {
VStack(alignment: .leading, spacing: 20.0) {
Text(item.title)
.font(.largeTitle)
.foregroundColor(.primary)
Text(item.textBody)
.font(.body)
.foregroundColor(.secondary)
.lineLimit(2)
BigDivider()
}
}.listRowSeparatorTint(.primary)
.listRowSeparator(.hidden)
}
else {
if item.title.localizedCaseInsensitiveContains(searchText) || item.textBody.localizedCaseInsensitiveContains(searchText){
NavigationLink(destination: FavoriteDetailView(item: item)) {
VStack(alignment: .leading, spacing: 20.0) {
Text(item.title)
.font(.largeTitle)
.foregroundColor(.primary)
Text(item.textBody)
.font(.body)
.foregroundColor(.secondary)
.lineLimit(2)
BigDivider()
}
}.listRowSeparatorTint(.primary)
.listRowSeparator(.hidden)
}
}
}
.onDelete(perform: delete)
.onMove(perform: onMove)
}
.searchable(text: $searchText) {}
```
Without the rest of the code to test, I can't be sure, but you should be able to condense your code like so:
struct FavoriteView: View {
@EnvironmentObject var blindzeln: BLINDzeln
@State private var searchText = ""
var body: some View {
NavigationView {
List{
ForEach(blindzeln.favorites.filter { searchText.isEmpty ||($0.title.localizedCaseInsensitiveContains(searchText) || $0.textBody.localizedCaseInsensitiveContains(searchText)) }, id: \.entryID){ item in
NavigationLink(destination: FavoriteDetailView(item: item)) {
VStack(alignment: .leading, spacing: 20.0) {
Text(item.title)
.font(.largeTitle)
.foregroundColor(.primary)
Text(item.textBody)
.font(.body)
.foregroundColor(.secondary)
.lineLimit(2)
BigDivider()
}
}.listRowSeparatorTint(.primary)
.listRowSeparator(.hidden)
}
}
.onDelete(perform: delete)
.onMove(perform: onMove)
}
.searchable(text: $searchText) {}
// Nothing changed past here...
}
}
Essentially the filter I set up is this:
searchText
is empty, return TRUE so the item is used;searchText
is not empty, evaluate the other side of the OR which is 2 conditions with an OR. If either title
OR textBody
contains searchText
, return TRUE so item is used;One last thing, rename your entryID
in your model struct to id
, make the model struct conform to Identifiable
and then your ForEach
(leaving out the .filter
can be this:
ForEach(blindzeln.favorites) { item in
as an Identifiable
struct does not need to use id:
in a ForEach
initializer.