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

Live Activity自定义进度视图问题:fractionCompleted始终为0如何解决?

解决Live Activity中自定义ProgressViewStyle的fractionCompleted始终为0的问题

问题场景

我在实现Live Activity时,默认线性ProgressView使用timerInterval参数能正常随时间更新进度:

ProgressView(
    timerInterval: Date()...context.state.deliveryTime,
    countsDown: false,
    label: { EmptyView() },
    currentValueLabel: { EmptyView() }
)

但自定义EmojiProgressViewStyle实现带移动小车的进度视图时,configuration.fractionCompleted始终返回0,导致进度条和小车无法随时间移动:

struct EmojiProgressViewStyle: ProgressViewStyle {
    var emoji: String
    func makeBody(configuration: Configuration) -> some View {
        GeometryReader { geometry in
            ZStack(alignment: .leading) {
                RoundedRectangle(cornerRadius: 10)
                    .foregroundColor(Color.gray.opacity(0.3))
                    .frame(width: geometry.size.width, height: 10)
                
                RoundedRectangle(cornerRadius: 10)
                    .foregroundColor(.purple)
                    .frame(width: geometry.size.width * CGFloat(configuration.fractionCompleted ?? 0.1), height: 10)
                
                Text(emoji)
                    .frame(width: 20, height: 20)
                    .background(.clear)
                    .cornerRadius(10)
                    .position(x: geometry.size.width * CGFloat(configuration.fractionCompleted ?? 0.1), y: 5)
            }
        }
    }
}

问题原因

使用ProgressView(timerInterval:)初始化时,系统内部直接管理进度渲染逻辑,并未将进度值绑定到标准的Progress实例上,因此自定义ProgressViewStyle的configuration.fractionCompleted无法获取到实时的时间进度值。

解决方法

手动计算时间进度,将起始时间与结束时间传递给自定义样式,在样式内部实时计算当前进度占比:

1. 修改自定义ProgressViewStyle

新增起始/结束时间参数,内部实现进度计算逻辑:

struct EmojiProgressViewStyle: ProgressViewStyle {
    var emoji: String
    let startDate: Date
    let endDate: Date
    
    // 实时计算进度占比
    private var fractionCompleted: Double {
        let totalDuration = endDate.timeIntervalSince(startDate)
        guard totalDuration > 0 else { return 0 }
        let elapsedTime = Date().timeIntervalSince(startDate)
        // 限制进度在0-1之间
        return max(0, min(1, elapsedTime / totalDuration))
    }
    
    func makeBody(configuration: Configuration) -> some View {
        GeometryReader { geometry in
            ZStack(alignment: .leading) {
                RoundedRectangle(cornerRadius: 10)
                    .foregroundColor(Color.gray.opacity(0.3))
                    .frame(width: geometry.size.width, height: 10)
                
                RoundedRectangle(cornerRadius: 10)
                    .foregroundColor(.purple)
                    .frame(width: geometry.size.width * CGFloat(fractionCompleted), height: 10)
                
                Text(emoji)
                    .frame(width: 20, height: 20)
                    .background(.clear)
                    .cornerRadius(10)
                    .position(x: geometry.size.width * CGFloat(fractionCompleted), y: 5)
            }
            // 添加平滑动画,匹配默认ProgressView的效果
            .animation(.linear(duration: 1), value: fractionCompleted)
        }
    }
}

2. 使用自定义样式

传入起始时间与结束时间参数:

ProgressView()
    .progressViewStyle(EmojiProgressViewStyle(
        emoji: "🚗",
        startDate: Date(),
        endDate: context.state.deliveryTime
    ))

倒计时场景适配

如果需要实现倒计时效果(对应原countsDown: true),只需修改进度计算逻辑:

private var fractionCompleted: Double {
    let totalDuration = endDate.timeIntervalSince(startDate)
    guard totalDuration > 0 else { return 0 }
    let remainingTime = endDate.timeIntervalSince(Date())
    return max(0, min(1, remainingTime / totalDuration))
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 19:05:27