提问者:小点点

使用For每步进器SwiftUI递增多个结构变量


我有一份比萨配料清单。列表中的每一项都是一个结构:

struct Topping: Identifiable {
    let name: String
    let price: Double
    @State var amount: Int
    let id = UUID()
}

该列表在MenuDataService.swift文件中的类中创建,使用static let定义,然后在ViewModel文件中初始化:

//FILE MenuDataService.swift
Class MenuDataService {
    static let toppingsList: [Topping] = [Topping(name: "Cheese", price: 3.00, amount: 0), Topping(name: "Sauce", price: 3.00, amount: 0)]
}

//FILE MenuViewModel.swift
Class MenuViewModel: ObservableObject {
    @Published var toppingsList: [Topping]
    init() {
        toppingsList = MenuDataService.toppingsList
        self.toppingsList = toppingsList
    }
}

在视图中,我使用视图中的 .environmentobject 访问对象。我正在使用 ForEach 循环迭代浇头列表,显示浇头的名称和数量,然后是一个步进器,它应该增加或减少“数量”变量。

@EnvironmentObject private var vm = MenuViewModel
let toppingsList: [Topping]
var body: some View {
    VStack {
        ForEach(toppingsList, id: \.id) { topping in
            Stepper("\(topping.name): \(topping.amount)", value: topping.$amount)
        }
    }
}

struct ExtraToppingsView_Previews: PreviewProvider {
    static var previews: some View {
        ExtraToppingsView(toppingsList: MenuViewModel.init().toppingsList)
        .environmentObject(MenuViewModel())
    }
}

我在 Stepper() 代码行中收到此错误:在视图上安装之外访问状态的值。这将导致初始值的常量绑定,并且不会更新。

在“Cheese”步进器中单击“”时,它应该增加变量,并将标题更改为“Cheese: 1”,但标题保持不变。我假设这与“@State var amount”变量有关,或者与步进器中的“$amount”变量有某种绑定。如果有人能给我指出正确的方向,我将不胜感激。


共1个答案

匿名用户

你的大部分代码都是封闭的——只有细微的差别才能让它工作。查看我的更改的内嵌注释:

struct Topping: Identifiable {
    let id = UUID()
    let name: String
    let price: Double
    var amount: Int //don't include `@State` in non-Views
}

//no changes
class MenuDataService {
    static let toppingsList: [Topping] = [Topping(name: "Cheese", price: 3.00, amount: 0), Topping(name: "Sauce", price: 3.00, amount: 0)]
}

class MenuViewModel: ObservableObject {
    @Published var toppingsList: [Topping]
    init() {
        toppingsList = MenuDataService.toppingsList
        //remove unnecessary duplicate assignment
    }
}

//This is the parent view -- may be called something different in your code
struct ContentView : View {
    @StateObject private var vm = MenuViewModel() //declare as @StateObject
    
    var body: some View {
        ExtraToppingsView()
            .environmentObject(vm) //pass the environment object
    }
}

struct ExtraToppingsView : View {
    @EnvironmentObject private var vm : MenuViewModel //no need to take the toppingsList parameter separately -- just use the environment object 

    var body: some View {
        VStack {
            ForEach($vm.toppingsList) { $topping in //use element binding to get a mutable binding to each item
                Stepper("\(topping.name): \(topping.amount)", value: $topping.amount) //see change of the position of the $ character
            }
        }
    }
}

struct ExtraToppingsView_Previews: PreviewProvider {
    static var previews: some View {
        ExtraToppingsView()
            .environmentObject(MenuViewModel())
    }
}

有关元素绑定的详细信息:https://www.swiftbysundell.com/articles/bindable-swiftui-list-elements/

相关问题