我正在嘗試制作兩個List組件:一個是靜態的和小的,第二個是非常大的和動態的。在第一個中,List我存盤食物類別:酒類產品、湯、谷物等。在第二個中List,直接從資料庫中搜索該詞——它可以是任何東西:一道菜或一類菜肴。下面是代碼 - 它顯示起始頁。最初,第一個 static 和 smallList位于其上,以及 Search 組件 ( Navigationview.seacrhable())。當你在搜索欄中輸入一個詞時,第一個List消失,第二個出現。目前,兩個作業表都是異步加載的。這是必要的,因為第二張紙真的很大(數千行)。這就是我的問題開始的地方。有時,當您在搜索欄中鍵入一個詞時,該作業表的副本會出現在它的頂部,如圖所示。它只發生了幾分之一秒,但仍然很明顯。問題很可能是由于異步加載,在我添加它之前,List加載速度非常慢,但沒有這樣的錯誤。
我的最小可重現示例:
內容視圖.sfiwt
主串列,顯示可供選擇的食物類別。
import SwiftUI
struct ContentView: View {
@Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
@State public var addScreen: Bool = true
@State private var searchByWordView: Bool = true
@State private var searchByWordCategoryView: Bool = true
@State public var gram: String = ""
@State private var selectedFood: String = ""
@State private var selectedFoodCategoryItem: String = ""
@State private var selectedFoodTemp: String = ""
@State private var selectedFoodCategoryTemp: String = ""
@State private var FoodCList: [FoodCategory] = []
@State private var FoodList: [FoodItemByName] = []
@State var foodItems: [String] = []
@MainActor
var body: some View {
NavigationView {
ZStack {
List {
if !searchByWordView {
Section {
ForEach(FoodList, id:\.self){i in
Button(action: {
selectedFoodTemp = i.name
addScreen.toggle()
}){Text("\(i.name)")}.foregroundColor(.black)
}
}
} else {
Section {
ForEach(FoodCList, id:\.self){i in
NavigationLink(destination: GetFoodCategoryItemsView(category: "\(i.name)")) {
Text("\(i.name)")
}.foregroundColor(.black)
}
}
}
}
.listStyle(.plain)
.task{
FoodCList = await FillFoodCategoryList()
}
if !addScreen {
addSreenView(addScreen: $addScreen, gram: $gram, selectedFood: $selectedFoodTemp, foodItems: $foodItems)
}
}
.navigationTitle("Add the dish")
.navigationBarTitleDisplayMode(.inline)
}
.searchable(
text: $selectedFood,
placement: .navigationBarDrawer(displayMode: .always),
prompt: "Search by word"
)
.onChange(of: selectedFood, perform: {i in
if i.isEmpty {
searchByWordView = true
} else {
searchByWordView = false
Task {
FoodList = await GetFoodItemsByName(_name: selectedFood)
}
}
})
}
func GetFoodCategoryItemsView(category: String) -> some View {
ZStack {
List {
if !searchByWordCategoryView {
Section {
ForEach(GetFoodCategoryItems(_category: category).filter{$0.name.contains(selectedFoodCategoryItem)}, id:\.self){i in
Button(action: {
selectedFoodCategoryTemp = i.name
addScreen.toggle()
}){Text("\(i.name)")}
}
}
} else {
Section {
ForEach(GetFoodCategoryItems(_category: category), id:\.self){i in
Button(action: {
selectedFoodCategoryTemp = i.name
addScreen.toggle()
}){Text("\(i.name)")}
}
}
}
}
if !addScreen {
addSreenView(addScreen: $addScreen, gram: $gram, selectedFood: $selectedFoodCategoryTemp, foodItems: $foodItems)
}
}
.searchable(
text: $selectedFoodCategoryItem,
placement: .navigationBarDrawer(displayMode: .always),
prompt: "Search by word"
)
.onChange(of: selectedFoodCategoryItem, perform: {i in
if i.isEmpty {
searchByWordCategoryView = true
} else {
searchByWordCategoryView = false
}
})
.listStyle(.plain)
.navigationTitle(category)
.navigationBarTitleDisplayMode(.inline)
.interactiveDismissDisabled()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
添加SreenView.swift
輸入消耗的食物克數的模態視窗。
import SwiftUI
struct addSreenView: View {
@Binding var addScreen: Bool
@Binding var gram: String
@Binding var selectedFood: String
@Binding var foodItems: [String]
var body: some View {
ZStack{
Color(.black)
.opacity(0.3)
.ignoresSafeArea()
.onTapGesture{withAnimation(.linear){addScreen.toggle()}}
VStack(spacing:0){
Text("Add a dish/meal")
.padding()
Divider()
VStack(){
TextField("Weight, in gram", text: $gram)
.padding(.leading, 16)
.padding(.trailing, 16)
Rectangle()
.frame(height: 1)
.foregroundColor(.black)
.padding(.leading, 16)
.padding(.trailing, 16)
}.padding()
Divider()
HStack(){
Button(action: {
foodItems.append("\(selectedFood), \(gram) g.")
gram = ""
selectedFood = ""
addScreen.toggle()
}){
Text("Save")
.frame(maxWidth: .infinity)
.foregroundColor(.black)
}
.frame(maxWidth: .infinity)
Divider()
Button(action: {
gram = ""
selectedFood = ""
addScreen.toggle()
}){
Text("Cancel")
.frame(maxWidth: .infinity)
.foregroundColor(.black)
}
.frame(maxWidth: .infinity)
}.frame(height: 50)
}
.background(Color.white.cornerRadius(10))
.frame(maxWidth: 350)
}
}
}
GetFunction.swift
這個檔案模擬了我真實的 SQLite 資料庫查詢。
import Foundation
import SwiftUI
// Fill start pade List (all categories of dishes)
struct FoodCategory: Identifiable, Hashable {
let name: String
let id = UUID()
}
func FillFoodCategoryList() async -> [FoodCategory] {
let catList: [FoodCategory] = [FoodCategory(name: "Alcohol"),FoodCategory(name: "Soups"),FoodCategory(name: "Cereals"),FoodCategory(name: "Fish"),FoodCategory(name: "Meat")]
return catList
}
// Search by word List
struct FoodItemByName: Identifiable, Hashable {
let name: String
let id = UUID()
}
func GetFoodItemsByName(_name: String) async -> [FoodItemByName] {
var foodItemsByName: [FoodItemByName] = []
let items: [String] = ["Light beer with 11% dry matter in the original wort","Light beer with 20% of dry matter in the original wort","Dark beer with 13% dry matter content in the original wort","Dark beer, with a proportion of dry substances in the initial wort of 20%","Dry white and red wines (including champagne)","Semi-dry white and red wines (including champagne)","Semi-sweet white and red wines (including champagne)","Sweet white and red wines (including champagne)","Strong wines","Semi-dessert wines","Dessert wines","Liqueur wines","Slivyanka liqueur","Cherry liqueur","Ordinary cognac - Three stars","Vodka"]
let filteredItems = items.filter{ $0.contains("\(_name)") }
for i in filteredItems {
foodItemsByName.append(FoodItemByName(name: i))
}
return foodItemsByName
}
// List appears when you click on Alcohole in start page (by analogy with other categories of dishes)
struct FoodCategoryItem: Identifiable, Hashable {
let name: String
let id = UUID()
}
func GetFoodCategoryItems(_category: String) -> [FoodCategoryItem] {
var foodCategoryItems: [FoodCategoryItem] = []
let _alcohole: [String] = ["Light beer with 11% dry matter in the original wort","Light beer with 20% of dry matter in the original wort","Dark beer with 13% dry matter content in the original wort","Dark beer, with a proportion of dry substances in the initial wort of 20%","Dry white and red wines (including champagne)","Semi-dry white and red wines (including champagne)","Semi-sweet white and red wines (including champagne)","Sweet white and red wines (including champagne)","Strong wines","Semi-dessert wines","Dessert wines","Liqueur wines","Slivyanka liqueur","Cherry liqueur","Ordinary cognac - Three stars","Vodka"]
let _soup: [String] = ["Chicken soup","French onion soup","Tomato soup","Chicken Dumpling Soup","Beef Stew","Cream of Potato","Lobster Bisque","Chili Con Carne","Clam Chowder","Cream Of Cheddar Broccoli"]
let _cereals: [String] = ["Cinnamon Toast Crunch","Frosted Flakes","Honey Nut Cheerios","Lucky Charms","Froot Loops","Fruity Pebbles","Cap'n Crunch","Cap'n Crunch's Crunch Berries","Cocoa Puffs","Reese's Puffs"]
let _fish: [String] = ["Salmon","Tuna","Cod","Rainbow Trout","Halibut","Red Snapper","Flounder","Bass","Mahi-Mahi","Catfish"]
let _meat: [String] = ["Beef","Chicken (Food)","Lamb","Pork","Duck","Turkey","Venison","Buffalo","American Bison"]
if _category == "Alcohol"{
for i in _alcohole{foodCategoryItems.append(FoodCategoryItem(name: i))}
} else if _category == "Soups" {
for i in _soup{foodCategoryItems.append(FoodCategoryItem(name: i))}
} else if _category == "Cereals" {
for i in _cereals{foodCategoryItems.append(FoodCategoryItem(name: i))}
} else if _category == "Fish" {
for i in _fish{foodCategoryItems.append(FoodCategoryItem(name: i))}
} else {
for i in _meat{foodCategoryItems.append(FoodCategoryItem(name: i))}
}
return foodCategoryItems
}

uj5u.com熱心網友回復:
除了id用于 ID 之外,如評論中所述,您可以進行一些重構以使 SwiftUI 不重新渲染盡可能多的視圖層次結構,而是重用組件。例如,你有一個if條件,并在每次有單獨的Section,ForEach等部件。相反,您可以ForEach根據搜索狀態呈現 的內容:
func categoryItems(category: String) -> [FoodCategoryItem] {
if !searchByWordCategoryView {
return GetFoodCategoryItems(_category: category).filter{$0.name.contains(selectedFoodCategoryItem)}
} else {
return GetFoodCategoryItems(_category: category)
}
}
func GetFoodCategoryItemsView(category: String) -> some View {
ZStack {
List {
Section {
ForEach(categoryItems(category: category)){i in
Button(action: {
selectedFoodCategoryTemp = i.name
addScreen.toggle()
}){Text("\(i.name)")}
}
}
if !addScreen {
addSreenView(addScreen: $addScreen, gram: $gram, selectedFood: $selectedFoodCategoryTemp, foodItems: $foodItems)
}
}
}
.searchable(
text: $selectedFoodCategoryItem,
placement: .navigationBarDrawer(displayMode: .always),
prompt: "Search by word"
)
.onChange(of: selectedFoodCategoryItem, perform: {i in
if i.isEmpty {
searchByWordCategoryView = true
} else {
searchByWordCategoryView = false
}
})
.listStyle(.plain)
.navigationTitle(category)
.navigationBarTitleDisplayMode(.inline)
.interactiveDismissDisabled()
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/369154.html
