You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI基于Stand模型创建可独立绑定数组的实现求助

问题解决:独立绑定Stand模型并实现面积计算

问题说明

列表项数量由用户输入的“Number of Stands”决定,但原代码中所有StandRowView绑定同一个speed变量,导致输入速度时所有行同步变化。需实现:

  • 每行数据与Stand模型关联,实现独立数据绑定
  • 通过.onChange监听数据变化,计算相邻Stand的面积比值并更新右侧文本

修改后的完整代码

1. Stand 模型定义

调整属性类型以支持计算,添加动态初始化方法:

import Foundation
import SwiftUI

struct Stand: Codable, Identifiable, Hashable {
    var id: String { stand }
    var stand: String
    var area: Double // 改为Double类型方便数值计算
    var speed: Int
    var rf: Double // 存储当前Stand与下一个Stand的面积比值

    // 根据工位序号和初始面积创建实例
    init(standNumber: Int, initialArea: Double) {
        self.stand = "\(standNumber)"
        self.area = initialArea
        self.speed = 0
        self.rf = 0.0
    }
}

2. StandRowView 行视图

直接绑定整个Stand对象,实现独立数据管理:

import SwiftUI

struct StandRowView: View {
    @Binding var stand: Stand

    var body: some View {
        HStack {
            Text("Stand")
            Text(stand.stand)
            TextField("Enter Speed", value: $stand.speed, format: .number)
                .frame(width: 110, height: 40)
                .foregroundColor(.black)
                .multilineTextAlignment(.center)
                .background(Color.white)
                .border(Color.gray, width: 1)
                .cornerRadius(10)
                .padding(.trailing, 30)
            // 显示计算后的面积比值,保留两位小数
            Text(String(format: "%.2f", stand.rf))
        }
        .padding()
    }
}

3. Speeds1View 主视图

使用数组存储所有Stand数据,动态创建列表项,自动计算面积比值:

import SwiftUI

struct Speeds1View: View {
    let title: String
    let productArea: Double
    let noStands: Int
    let billetArea: Double
    @Environment(\.dismiss) var dismiss
    @State private var stands: [Stand] = []

    // 计算总压缩比
    private var reductionRatio: Double {
        billetArea / productArea
    }

    // 计算平均面积压缩率
    private var averageAreaReduction: Double {
        let ratioPerStand = pow(reductionRatio, 1.0 / Double(noStands))
        return (1 - 1/ratioPerStand) * 100
    }

    var body: some View {
        NavigationStack {
            List {
                // 顶部信息栏
                VStack(spacing: 8) {
                    Text("# of Stands")
                    Text("\(noStands)")
                    Text("Billet Area")
                    Text(String(format: "%.2f", billetArea))
                    Text("Product Area")
                    Text(String(format: "%.2f", productArea))
                    Text("Reduction Ratio: \(String(format: "%.2f", reductionRatio)) : 1")
                    Text("Ave. Area Red: \(String(format: "%.1f", averageAreaReduction))%")
                }
                .frame(maxWidth: .infinity)
                .padding(.vertical)

                // 动态生成Stand行
                ForEach($stands) { $stand in
                    StandRowView(stand: $stand)
                        .listRowInsets(EdgeInsets())
                        .listRowSeparator(.hidden)
                }
            }
            .onAppear {
                // 初始化Stand数组,按等比例压缩分配初始面积
                let initialAreas = calculateInitialAreas()
                stands = (1...noStands).enumerated().map { index, number in
                    Stand(standNumber: number, initialArea: initialAreas[index])
                }
                // 首次计算面积比值
                calculateRatios()
            }
            .onChange(of: stands) { _, _ in
                // 任何Stand数据变化时,重新计算比值
                calculateRatios()
            }
            .toolbar {
                ToolbarItem(placement: .navigationBarLeading) {
                    Button(action: dismiss) {
                        Image(systemName: "arrowshape.turn.up.backward")
                            .font(.footnote)
                            .foregroundColor(.blue)
                    }
                }
                ToolbarItem(placement: .navigationBarTrailing) {
                    Button(action: {
                        // 可添加保存/导出逻辑
                    }) {
                        Image(systemName: "square.and.arrow.up")
                            .resizable()
                            .frame(width: 20, height: 25)
                            .foregroundStyle(Color.blue, Color.gray)
                    }
                }
            }
            .navigationBarTitleDisplayMode(.inline)
            .navigationTitle("Calculate Area, \(title)")
        }
    }

    // 按等比例压缩逻辑计算每个Stand的初始面积
    private func calculateInitialAreas() -> [Double] {
        var areas: [Double] = []
        var currentArea = billetArea
        let ratioPerStand = pow(reductionRatio, 1.0 / Double(noStands))
        
        for _ in 1...noStands {
            areas.append(currentArea)
            currentArea /= ratioPerStand
        }
        
        // 确保最后一个Stand的面积与产品面积一致
        if !areas.isEmpty {
            areas[areas.count - 1] = productArea
        }
        return areas
    }

    // 计算每个Stand与下一个Stand的面积比值
    private func calculateRatios() {
        for index in 0..<stands.count {
            if index < stands.count - 1 {
                stands[index].rf = stands[index].area / stands[index + 1].area
            } else {
                // 最后一个Stand无后续工位,比值设为1.0
                stands[index].rf = 1.0
            }
        }
    }
}

核心修改说明

  • 用@State [Stand]数组替代单个变量,实现每行数据独立存储
  • StandRowView直接绑定Stand对象,确保输入操作只影响当前行
  • 通过.onAppear和.onChange自动触发面积比值计算,实时更新UI
  • 调整模型属性类型为数值型,方便后续计算逻辑扩展

内容的提问来源于stack exchange,提问作者johnny

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 14:35:04