SwiftUI Почему мои кнопки в моем списке перестают работать, если у меня слишком много элементов в списке? - PullRequest
1 голос
/ 27 января 2020

HELP! Я не могу понять это!

Чтобы помочь мне изучить 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()
    }
}

Ответы [ 2 ]

1 голос
/ 28 января 2020

Ну, в данном случае это проблема моделирования ... @State является свойством состояния представления, поэтому List, имеющий кэшированные представления, для оптимизации и повторного использования, сохраняет само внутреннее состояние представления. Таким образом, в таком сценарии ios состояние не может быть использовано в целях обеспечения устойчивости, и требуется наличие явной модели представления, и фактически это верно для всех случаев модели.

Здесь приведен модифицированный демонстрационный код с использованием модели представления на основе на 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: $0) } // 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()
    }
}
0 голосов

Как я видел ранее , List ведет себя странно при прокрутке, но иногда это нормально работает на устройстве. Попробуйте заменить List на ScrollView, последний не имеет этих ошибок.

...