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

