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
相关产品推荐
相关产品推荐

