灵动岛
了解如何在 EasyAppSwiftUI 中实现灵动岛功能
简介
EasyAppWidgetLiveActivity 基于 ActivityKit 构建,支持锁屏横幅与灵动岛动态展示。本文介绍如何利用 EasyAppWidgetAttributes 和组件化视图在灵动岛上呈现扩展信息,并确保主应用与扩展间的数据同步。
架构概览
- Widget 配置
EasyAppWidgetLiveActivity使用ActivityConfiguration,在dynamicIsland闭包中为扩展、紧凑与最小区域分别提供 SwiftUI 视图。 - 视图组件 所有灵动岛区域视图定义在
EasyAppSwiftUI/EasyAppWidget/WidgetsComponents/LiveActivityComponents.swift。 - 数据模型
EasyAppWidgetAttributes与EasyAppWidgetAttributes.ContentState必须在主应用与 Widget Extension 中保持完全一致(字段、初始化器),否则 Live Activity 无法解码。
关键代码结构
struct EasyAppWidgetLiveActivity: Widget {
var body: some WidgetConfiguration {
ActivityConfiguration(for: EasyAppWidgetAttributes.self) { context in
LiveActivityLockScreen(
attributes: context.attributes,
state: context.state
)
.activityBackgroundTint(.clear)
.activitySystemActionForegroundColor(.primary)
} dynamicIsland: { context in
DynamicIsland {
DynamicIslandExpandedRegion(.leading) {
LiveActivityExpandedLeading(
attributes: context.attributes,
state: context.state
)
}
DynamicIslandExpandedRegion(.trailing) {
LiveActivityExpandedTrailing(
attributes: context.attributes,
state: context.state
)
}
DynamicIslandExpandedRegion(.bottom) {
LiveActivityExpandedBottom(
attributes: context.attributes,
state: context.state
)
}
} compactLeading: {
LiveActivityCompactLeading(attributes: context.attributes, state: context.state)
} compactTrailing: {
LiveActivityCompactTrailing(attributes: context.attributes, state: context.state)
} minimal: {
LiveActivityMinimal(attributes: context.attributes, state: context.state)
}
.widgetURL(URL(string: "easyapp://live-activity?path=live-activity"))
.keylineTint(.blue)
}
}
}.widgetURL为灵动岛提供点击跳转入口,可根据业务替换深链路径。.keylineTint控制灵动岛轮廓色彩,建议与品牌主色保持一致。
区域视图说明
- 扩展区域 (
LiveActivityExpandedLeading/Trailing/Bottom) 负责展示主要内容、状态指标与操作按钮,可根据属性或状态扩展更多自定义视图。 - 紧凑区域 (
LiveActivityCompactLeading/Trailing) 将信息压缩为图标与短文本,确保在灵动岛收起状态下仍可识别。 - 最小区域 (
LiveActivityMinimal) 采用动画渐变背景与 Emoji,适合展示运行中的状态提示。 - 锁屏横幅 (
LiveActivityLockScreen) 与灵动岛共用属性数据,保持视觉一致性,必要时可在此增加更丰富的操作卡片。
数据与状态管理
EasyAppWidgetAttributes描述 Live Activity 的静态属性,例如用户名或任务标题。EasyAppWidgetAttributes.ContentState保存实时字段(如 Emoji、进度值)。更新状态时,通过Activity.update(using:)推送到灵动岛。- 主应用和扩展中的
EasyAppWidgetAttributes文件路径分别为:EasyAppSwiftUI/Common/EasyAppWidgetAttributes.swiftEasyAppWidget/Common/EasyAppWidgetAttributes.swift请保持两处文件完全同步,以避免序列化失败。
启动与调试
- 在主应用启动 Live Activity:
let activity = try Activity<EasyAppWidgetAttributes>.request( attributes: EasyAppWidgetAttributes(name: "World"), contentState: EasyAppWidgetAttributes.ContentState(emoji: "😀"), pushType: nil ) - 运行
EasyAppWidgetExtensionscheme,确保模拟器或设备支持灵动岛(iPhone 14 Pro 及以上)。 - 在 Xcode 的
#Preview区域查看.dynamicIsland(.compact/.expanded/.minimal)预览,快速校验布局。 - 使用
activity.update(using:)调整ContentState,观察灵动岛的动态效果。
设计与交互建议
- 遵循 Apple 人机交互指南:紧凑区域文字尽量保持在 6~8 个字符内,避免溢出。
- 利用
AnimatedProgressBar、PulsingStatusIndicator等辅助视图在扩展区域展示实时状态。 - 操作按钮应通过
.buttonStyle(PlainButtonStyle())保持灵动岛无多余高亮背景,确保易读性。 - 若需要本地化,提前在
EasyAppWidgetAttributes中准备对应文案或通过LocalizedStringResource管理。
常见问题
- Live Activity 无法启动:确认主应用
Info.plist包含NSSupportsLiveActivities = true,并在真机环境测试。 - 属性解码失败:检查主应用与扩展的
EasyAppWidgetAttributes.ContentState是否字段一致(参考团队经验,切勿新增未同步的属性)。 - 灵动岛不显示按钮:确认
DynamicIslandExpandedRegion中的按钮未被条件隐藏,并在交互时调用实际逻辑。 - 预览编译报错:如预览依赖运行时代码,可在预览目标中提供 mock 数据或加
#if DEBUG限制。
更多灵动岛布局示例可在 LiveActivityComponents.swift 底部的多个 #Preview 中查阅,涵盖紧凑、扩展、锁屏等场景。
Last updated on