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

SwiftUI状态跟踪视图问题:非数组传参、图片不更新及代码简化

问题解决方案

1. 不修改OrderStatus类型实现UI视图

保持OrderStatus为Int枚举的前提下,无需将其改为数组类型,只需在枚举中添加静态属性定义状态跟踪的步骤序列,即可为视图提供数据源:

public enum OrderStatus: Int {
    // 原有case保持不变
    case some1 = 10
    case some2 = 20
    case some3 = 30
    case some4 = 40
    case some5 = 50
    case some6 = 60
    case some7 = 99
    
    // 定义需要展示的跟踪步骤序列
    static let trackingSteps: [OrderStatus] = [.some3, .some4, .some5]
    
    // 原有属性保持不变
    var text: String { /* ... */ }
    var title: String { /* ... */ }
}

视图直接使用OrderStatus.trackingSteps作为步骤数据源,无需修改枚举的核心类型结构。

2. 实现图片的动态更新

当前isCompleted()方法硬编码完成状态,无法根据实际订单状态动态判断。需要调整逻辑,让步骤的完成状态依赖于当前订单的状态:

  • 给StatusTrackingView添加currentStatus属性,传入当前订单的实际状态:
struct StatusTrackingView: View {
    let currentStatus: OrderStatus
    private let steps = OrderStatus.trackingSteps
    
    // ... 其他代码 ...
}
  • 添加动态判断完成状态的方法:
private func isCompleted(for step: OrderStatus) -> Bool {
    // 通过rawValue比较,当前状态数值大于等于步骤数值则视为已完成
    currentStatus.rawValue >= step.rawValue
}

private func isCurrentStep(for step: OrderStatus) -> Bool {
    // 判断是否为当前正在进行的步骤
    currentStatus == step
}
  • 在视图中动态选择图标:
Image(isCompleted(for: step) ? Icon.badgeConditionComplete : 
     isCurrentStep(for: step) ? Icon.badgeConditionCurrent : 
     Icon.badgeConditionIncomplete)

3. 代码简化与优化要点

3.1 避免遍历indices,直接遍历数组元素

替换原有的ForEach(steps.indices)为直接遍历元素,代码更简洁易读:

ForEach(steps, id: \.self) { step in
    // 直接使用step,无需通过index索引获取
}

3.2 移除硬编码布局数值

将布局中固定的数值定义为常量,提升可维护性:

private let iconSize: CGFloat = 24
private let progressBarHeight: CGFloat = 4
private let stepTextWidth: CGFloat = 46.5

3.3 封装重复视图组件

将进度条片段封装为独立视图,减少代码冗余:

struct ProgressSegment: View {
    let isFilled: Bool
    let progress: CGFloat
    private let barHeight: CGFloat = 4
    
    var body: some View {
        ZStack(alignment: .leading) {
            Rectangle()
                .fill(Color.Gray.light)
                .frame(height: barHeight)
            Rectangle()
                .fill(Color.Primary.base)
                .frame(width: isFilled ? .infinity : progress * UIScreen.main.bounds.width / 3, height: barHeight)
                .clipShape(RoundedRectangle(cornerRadius: 2))
        }
    }
}

3.4 简化进度计算逻辑

通过当前状态在步骤序列中的索引,简化进度判断:

private var currentStepIndex: Int {
    steps.firstIndex(of: currentStatus) ?? 0
}

private func progressForSegment(at index: Int) -> CGFloat {
    if index < currentStepIndex {
        return 1.0
    } else if index == currentStepIndex {
        return 0.6
    } else {
        return 0.0
    }
}

完整修改后的代码

OrderStatus枚举

public enum OrderStatus: Int {
    case some1 = 10
    case some2 = 20
    case some3 = 30
    case some4 = 40
    case some5 = 50
    case some6 = 60
    case some7 = 99
    
    var text: String {
        switch self {
        case .some3: return "步骤3"
        case .some4: return "步骤4"
        case .some5: return "步骤5"
        default: return ""
        }
    }
    
    var title: String {
        switch self {
        case .some3: return "第三步"
        case .some4: return "第四步"
        case .some5: return "第五步"
        default: return ""
        }
    }
    
    static let trackingSteps: [OrderStatus] = [.some3, .some4, .some5]
}

StatusTrackingView视图

struct StatusTrackingView: View {
    let currentStatus: OrderStatus
    private let steps = OrderStatus.trackingSteps
    
    // 布局常量
    private let iconSize: CGFloat = 24
    private let stepTextWidth: CGFloat = 46.5
    
    var body: some View {
        VStack(spacing: 8) {
            HStack(spacing: 8) {
                ForEach(Array(steps.enumerated()), id: \.element) { index, step in
                    let isCompleted = isCompleted(for: step)
                    let isCurrent = isCurrentStep(for: step)
                    
                    Image(isCompleted ? Icon.badgeConditionComplete : 
                         isCurrent ? Icon.badgeConditionCurrent : 
                         Icon.badgeConditionIncomplete)
                    .frame(width: iconSize, height: iconSize)
                    
                    if index < steps.count - 1 {
                        ProgressSegment(
                            isFilled: index < currentStepIndex,
                            progress: progressForSegment(at: index)
                        )
                    }
                }
            }
            
            HStack(spacing: 0) {
                ForEach(steps, id: \.self) { step in
                    Text(step.text)
                        .foregroundStyle(Color.Ink.base)
                        .font(Font.SFPro.textRegular(size: 10))
                        .frame(width: stepTextWidth)
                }
            }
        }
        .padding(.horizontal)
    }
    
    private var currentStepIndex: Int {
        steps.firstIndex(of: currentStatus) ?? 0
    }
    
    private func isCompleted(for step: OrderStatus) -> Bool {
        currentStatus.rawValue >= step.rawValue
    }
    
    private func isCurrentStep(for step: OrderStatus) -> Bool {
        currentStatus == step
    }
    
    private func progressForSegment(at index: Int) -> CGFloat {
        if index < currentStepIndex {
            return 1.0
        } else if index == currentStepIndex {
            return 0.6
        } else {
            return 0.0
        }
    }
}

struct ProgressSegment: View {
    let isFilled: Bool
    let progress: CGFloat
    private let barHeight: CGFloat = 4
    
    var body: some View {
        ZStack(alignment: .leading) {
            Rectangle()
                .fill(Color.Gray.light)
                .frame(height: barHeight)
            Rectangle()
                .fill(Color.Primary.base)
                .frame(width: isFilled ? .infinity : progress * UIScreen.main.bounds.width / 3, height: barHeight)
                .clipShape(RoundedRectangle(cornerRadius: 2))
        }
    }
}

#Preview {
    StatusTrackingView(currentStatus: .some4)
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 00:44:54