SwiftUI 如果列表视图中的项目太多,为什么列表视图中的按钮会停止工作?
SwiftUI Why do my buttons on my list view stop working if I have too many items on the list view?
求助!我想不通!
为了帮助我学习 SwiftUI,我正在使用列表视图制作一个简单的杂货清单应用程序。点击列表中的每个项目时,有些按钮会变成绿色或红色。
在我向列表数组中添加太多项目之前,下面的代码工作得很好。如果列表长于屏幕大小并且您必须滚动,那么奇怪的事情就会开始发生。 (例如按钮不会变成绿色或下一页上的项目变成绿色)
我用不同的模拟器进行了测试,在 iPhone SE 上,我可以在列表开始混乱之前得到 14 个项目。在 iPhone 11 Pro Max 上,我可以在列表开始混乱之前得到 22 个项目。跟屏幕尺寸的长度和是否需要滚动有关系。
代码如下:
import SwiftUI
struct CheckboxFieldView : View {
@State var checkState:Bool = false ;
var body: some View {
Button(action:
{
self.checkState = !self.checkState
}) {
Rectangle()
.fill(self.checkState ? Color.green : Color.red)
.frame(width:20, height:20, alignment: .center)
.cornerRadius(5)
}
.foregroundColor(Color.white)
}
}
struct ContentView: View {
// let items = (1...100).map { number in "Item \(number)" }
let items = ["Bread", "Milk", "Cheese", "Granola", "Nuts", "Cereal", "Rosemary", "Tomato Sauce", "Bean with Bacon Soup", "Tea", "Chocolate Milk", "Frozen Blueberries", "Frozen Mixed Berries", "Frozen Strawberries", "Grapes"]
var body: some View {
NavigationView {
List(items, id: \.self) { item in
HStack{
CheckboxFieldView()
Text(item)
self.padding()
Text ("Location")
}
}.navigationBarTitle("Grocery List", displayMode: .inline)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
正如我看到的 ,List
在滚动时有一些奇怪的行为,但有时它在设备上正常工作。尝试将List
替换为ScrollView
,最后一个没有这些错误。
好吧,在这种情况下,这是建模问题...@State
是视图状态 属性,因此 List
具有缓存视图,用于优化和重用目的,保留视图内部状态本身。因此在这种情况下,状态不能用于持久性目的,并且需要具有显式视图模型,实际上对于所有模型情况都是如此。
这是修改后的演示代码,使用基于ObservableObject
和@Binding
的视图模型进行视图间数据传递,工作正常...
import SwiftUI
import Combine
// model to keep groceries
struct FoodItem: Identifiable {
var id = UUID().uuidString
var title: String
var checked = false
}
// view model part
class FoodViewModel: ObservableObject {
@Published var items = [FoodItem]()
}
struct CheckboxFieldView : View {
@Binding var item: FoodItem // bind to represented model
var body: some View {
Button(action:
{
self.item.checked.toggle()
}) {
Rectangle()
.fill(self.item.checked ? Color.green : Color.red)
.frame(width:20, height:20, alignment: .center)
.cornerRadius(5)
}
.foregroundColor(Color.white)
}
}
struct ContentView: View {
@ObservedObject private var viewModel = FoodViewModel()
let items = ["Bread", "Milk", "Cheese", "Granola", "Nuts", "Cereal", "Rosemary", "Tomato Sauce", "Bean with Bacon Soup", "Tea", "Chocolate Milk", "Frozen Blueberries", "Frozen Mixed Berries", "Frozen Strawberries", "Grapes"]
init() {
viewModel.items = items.map { FoodItem(title: [=10=]) } // fill in demo model items
}
var body: some View {
NavigationView {
List(Array(viewModel.items.enumerated()), id: \.element.id) { (i, item) in
HStack{
CheckboxFieldView(item: self.$viewModel.items[i]) // bind to current item in view model
Text(item.title)
Spacer()
Text ("Location")
}
}.navigationBarTitle("Grocery List", displayMode: .inline)
}
}
}
struct TestListWithButtons_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
求助!我想不通!
为了帮助我学习 SwiftUI,我正在使用列表视图制作一个简单的杂货清单应用程序。点击列表中的每个项目时,有些按钮会变成绿色或红色。
在我向列表数组中添加太多项目之前,下面的代码工作得很好。如果列表长于屏幕大小并且您必须滚动,那么奇怪的事情就会开始发生。 (例如按钮不会变成绿色或下一页上的项目变成绿色)
我用不同的模拟器进行了测试,在 iPhone SE 上,我可以在列表开始混乱之前得到 14 个项目。在 iPhone 11 Pro Max 上,我可以在列表开始混乱之前得到 22 个项目。跟屏幕尺寸的长度和是否需要滚动有关系。
代码如下:
import SwiftUI
struct CheckboxFieldView : View {
@State var checkState:Bool = false ;
var body: some View {
Button(action:
{
self.checkState = !self.checkState
}) {
Rectangle()
.fill(self.checkState ? Color.green : Color.red)
.frame(width:20, height:20, alignment: .center)
.cornerRadius(5)
}
.foregroundColor(Color.white)
}
}
struct ContentView: View {
// let items = (1...100).map { number in "Item \(number)" }
let items = ["Bread", "Milk", "Cheese", "Granola", "Nuts", "Cereal", "Rosemary", "Tomato Sauce", "Bean with Bacon Soup", "Tea", "Chocolate Milk", "Frozen Blueberries", "Frozen Mixed Berries", "Frozen Strawberries", "Grapes"]
var body: some View {
NavigationView {
List(items, id: \.self) { item in
HStack{
CheckboxFieldView()
Text(item)
self.padding()
Text ("Location")
}
}.navigationBarTitle("Grocery List", displayMode: .inline)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
正如我看到的 List
在滚动时有一些奇怪的行为,但有时它在设备上正常工作。尝试将List
替换为ScrollView
,最后一个没有这些错误。
好吧,在这种情况下,这是建模问题...@State
是视图状态 属性,因此 List
具有缓存视图,用于优化和重用目的,保留视图内部状态本身。因此在这种情况下,状态不能用于持久性目的,并且需要具有显式视图模型,实际上对于所有模型情况都是如此。
这是修改后的演示代码,使用基于ObservableObject
和@Binding
的视图模型进行视图间数据传递,工作正常...
import SwiftUI
import Combine
// model to keep groceries
struct FoodItem: Identifiable {
var id = UUID().uuidString
var title: String
var checked = false
}
// view model part
class FoodViewModel: ObservableObject {
@Published var items = [FoodItem]()
}
struct CheckboxFieldView : View {
@Binding var item: FoodItem // bind to represented model
var body: some View {
Button(action:
{
self.item.checked.toggle()
}) {
Rectangle()
.fill(self.item.checked ? Color.green : Color.red)
.frame(width:20, height:20, alignment: .center)
.cornerRadius(5)
}
.foregroundColor(Color.white)
}
}
struct ContentView: View {
@ObservedObject private var viewModel = FoodViewModel()
let items = ["Bread", "Milk", "Cheese", "Granola", "Nuts", "Cereal", "Rosemary", "Tomato Sauce", "Bean with Bacon Soup", "Tea", "Chocolate Milk", "Frozen Blueberries", "Frozen Mixed Berries", "Frozen Strawberries", "Grapes"]
init() {
viewModel.items = items.map { FoodItem(title: [=10=]) } // fill in demo model items
}
var body: some View {
NavigationView {
List(Array(viewModel.items.enumerated()), id: \.element.id) { (i, item) in
HStack{
CheckboxFieldView(item: self.$viewModel.items[i]) // bind to current item in view model
Text(item.title)
Spacer()
Text ("Location")
}
}.navigationBarTitle("Grocery List", displayMode: .inline)
}
}
}
struct TestListWithButtons_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}