我有一個Country模型,然后有一個國家/地區的 JSON 串列。我已經使用ForEach. 如果搜索框為空,則值為filteredCountries整個串列,否則串列僅包含搜索框中包含內容的國家/地區。
問題是當串列被過濾并且我點擊favorite一個專案時,錯誤的國家被收藏了。索引與過濾的專案不匹配,它們仍然按順序排列:0,1,2,3等等。
國家
import Foundation
struct Country: Codable, Identifiable {
var id: String {image}
let display_name: String
let searchable_names: [String]
let image: String
var favorite: Bool
var extended: Bool
}
內容視圖
var filteredCountries : [Country] {
if (searchText.isEmpty) {
return countries;
} else {
return countries.filter { $0.display_name.contains(searchText) }
}
}
NavigationView {
ScrollView {
ForEach(Array(filteredCountries.enumerated()), id: \.1.id) { (index,country) in
LazyVStack {
ZStack(alignment: .bottom) {
Image("\(country.image)-bg")
.resizable()
.scaledToFit()
.edgesIgnoringSafeArea(.all)
.overlay(Rectangle().opacity(0.2))
.mask(
LinearGradient(gradient: Gradient(colors: [Color.black, Color.black.opacity(0)]), startPoint: .center, endPoint: .bottom)
)
HStack {
NavigationLink(
destination: CountryView(country: country),
label: {
HStack {
Image(country.image)
.resizable()
.frame(width: 50, height: 50)
Text(country.display_name)
.foregroundColor(Color.black)
.padding(.leading)
Spacer()
}
.padding(.top, 12.0)
}
).buttonStyle(FlatLinkStyle())
if country.favorite {
Image(systemName: "heart.fill").foregroundColor(.red).onTapGesture {
print(country)
countries[index].favorite.toggle()
}
.padding(.top, 12)
} else {
Image(systemName: "heart").foregroundColor(.red).onTapGesture {
print(country)
countries[index].favorite.toggle()
}
.padding(.top, 12)
}
}
.padding(.horizontal, 16.0)
}
}
.padding(.bottom, country.extended ? 220 : 0)
.onTapGesture {
withAnimation(.easeInOut(duration: 0.4)) {
self.countries[index].extended.toggle();
}
}
}
}
.frame(maxWidth: bounds.size.width)
.navigationTitle("Countries")
.font(Font.custom("Avenir-Book", size: 28))
}
.navigationViewStyle(StackNavigationViewStyle())
.searchable(text: $searchText, placement: .navigationBarDrawer(displayMode: .always), prompt: "Search Country")
uj5u.com熱心網友回復:
我做了一個簡單的演示,你可以試試。最值得注意的是filteredCountry型別[Binding<Country>]- 這允許我們改變元素,因為它是一個Binding. 在List/ForEach回圈中,使用$country因為我們傳入了一個Binding.
代碼:
struct ContentView: View {
@State private var countries: [Country] = ["Canada", "England", "France", "Germany", "US"]
@State private var search = ""
private var filteredCounties: [Binding<Country>] {
if search.isEmpty {
return $countries.map { $0 }
} else {
return $countries.filter { $country in
country.name.lowercased().contains(search.lowercased())
}
}
}
var body: some View {
NavigationView {
List(filteredCounties) { $country in
HStack {
Text(country.name)
Spacer()
Image(systemName: country.isFavorite ? "heart.fill" : "heart")
.foregroundColor(.red)
.onTapGesture {
country.isFavorite.toggle()
}
}
}
}
.navigationViewStyle(.stack)
.searchable(text: $search, prompt: "Canada")
}
}
下面的結構Country不是那么相關,但在這里是為了完整性:
struct Country: Identifiable, ExpressibleByStringLiteral {
let id = UUID()
let name: String
var isFavorite = false
init(stringLiteral value: StringLiteralType) {
name = value
}
}
結果:

uj5u.com熱心網友回復:
在里面
ForEach(Array(filteredCountries.enumerated()), id: \.1.id) { (index,country) in ....
該index指“新”陣列只包含一個過濾的國家,并非所有國家的原始陣列的索引。要訪問原始陣列項,您可以使用國家/地區 ID,例如:
if let ndx = countries.firstIndex(where: {$0.id == country.id}) {
countries[ndx].favorite.toggle()
}
代替:
countries[index].favorite.toggle()
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/396586.html
上一篇:二數和演算法背后的邏輯
