如何在Live Activity中添加可自定义的正常工作的ProgressView?
在Live Activity中实现自定义ProgressView的正确方式
可以在Live Activity中添加自定义ProgressView,但不能用普通Timer驱动进度更新——Live Activity的运行环境受WidgetKit限制,系统不会允许后台持续运行Timer,视图更新必须通过ActivityKit的状态同步机制触发。
你的代码问题分析
- Timer逻辑错误:初始
progress = 100.0,判断条件if progress > 100永远不成立,所以进度不会变化; - Live Activity运行机制限制:即使逻辑正确,前台App的
Timer.publish也无法在Live Activity的视图中生效,因为WidgetKit的视图刷新由系统调度,而非自定义Timer。
正确实现方案
通过ActivityKit的ActivityAttributes传递进度状态,系统会自动触发Live Activity视图刷新。
1. 定义Activity属性
首先创建包含进度信息的ActivityAttributes和ContentState:
import ActivityKit struct CustomProgressAttributes: ActivityAttributes { // 静态属性(可选,比如任务名称) var taskName: String // 动态状态(用于传递实时进度) public struct ContentState: Codable, Hashable { var currentProgress: Double var totalProgress: Double } }
2. 编写Live Activity视图
在Widget中使用ContentState的进度值渲染ProgressView:
import WidgetKit import SwiftUI struct CustomProgressLiveActivity: Widget { var body: some WidgetConfiguration { ActivityConfiguration(for: CustomProgressAttributes.self) { context in // 主视图(锁屏/通知中心显示) VStack(spacing: 8) { Text(context.attributes.taskName) .font(.headline) ProgressView(value: context.state.currentProgress, total: context.state.totalProgress) .progressViewStyle(LinearProgressViewStyle(tint: .systemBlue)) .padding(.horizontal) Text("\(Int(context.state.currentProgress))/\(Int(context.state.totalProgress))") .font(.caption) } .padding() .background(Color.systemBackground) } dynamicIsland: { context in // Dynamic Island视图(可选,适配iPhone 14+) DynamicIsland { DynamicIslandExpandedRegion(.center) { ProgressView(value: context.state.currentProgress, total: context.state.totalProgress) .padding() } } compactLeading: { Text("\(Int(context.state.currentProgress))") } compactTrailing: { ProgressView(value: context.state.currentProgress, total: context.state.totalProgress) .frame(width: 40) } minimal: { Text("\(Int(context.state.currentProgress))%") } .keylineTint(.systemBlue) } } }
3. 在App中更新进度
通过Activity.update(using:)方法同步进度状态,系统会自动刷新Live Activity视图:
import ActivityKit // 启动Live Activity func startCustomProgressActivity() { let attributes = CustomProgressAttributes(taskName: "自定义进度任务") let initialState = CustomProgressAttributes.ContentState(currentProgress: 0, totalProgress: 100) do { let activity = try Activity.request(attributes: attributes, contentState: initialState, pushType: nil) // 模拟进度更新(替换为实际业务逻辑) Task { for progress in 0...100 { try? await Task.sleep(nanoseconds: 1_000_000_000) // 每秒更新一次 await activity.update(using: CustomProgressAttributes.ContentState( currentProgress: Double(progress), totalProgress: 100 )) } // 结束Activity await activity.end(using: CustomProgressAttributes.ContentState( currentProgress: 100, totalProgress: 100 ), dismissalPolicy: .immediate) } } catch { print("启动Live Activity失败:\(error.localizedDescription)") } }
关键说明
- Live Activity的视图刷新完全依赖系统调度,只有更新
ContentState才能触发视图更新; - 避免在Live Activity视图中使用
@State+Timer的方式,这种模式仅适用于前台App; - 如果需要更复杂的自定义样式,可以通过
progressViewStyle自定义ProgressView的外观。
内容的提问来源于stack exchange,提问作者Empiric10
相关产品推荐
相关产品推荐

