WidgetKit — 基础概念
This article is extracted from the chat log with AI. Please identify it with caution.

WidgetKit 的基础概念 #

WidgetKit 是 Apple 推出的框架,用于在 iOS、iPadOS、watchOS 和 macOS 上创建 小组件(Widgets)。这些小组件是你应用的扩展,可以出现在主屏幕、锁屏、智能叠放或通知中心,为用户提供 快速查看信息 的能力,而无需打开完整的 App。

WidgetKit 的核心特点: #

  • 使用 SwiftUI 构建 UI:全部基于声明式编程。

  • 生命周期由系统控制:小组件不能自由刷新的时间,必须由系统决定。

  • 时间线驱动(Timeline):你需要为小组件提供一个“时间线”(TimelineEntry),系统会根据时间推进更新小组件内容。

  • 静态配置与动态配置:支持定义参数(如选择某个主题、过滤条件等)。

Widget 的结构: #

一个 Widget 通常包括以下几部分:

组件作用
TimelineProvider提供时间线和占位数据
TimelineEntry每一个特定时间点显示的数据
WidgetConfiguration声明 Widget 的基本信息与类型(静态/动态)
View用 SwiftUI 构建显示内容

WidgetKit 与 ActivityKit、App Intents 的关系 #

1. WidgetKit vs ActivityKit #

维度WidgetKitActivityKit
用途显示静态或半动态的 Widget(如天气、日历)显示正在进行的实时活动,如计时器、外卖配送
显示位置主屏幕、锁屏、通知中心锁屏、灵动岛(Dynamic Island)
刷新机制由时间线控制,受限实时更新(Live Activity),通过 Activity<ContentState>
内容类型通常是周期性信息或快照当前状态 + 动态进展(实时)
使用技术WidgetKit + TimelineActivityKit(底层仍然使用 WidgetKit 渲染 UI)

联系:Live Activity 本质上也是一种特殊类型的 Widget,它使用的是 WidgetKit 渲染 UI,但通过 ActivityKit 提供实时状态更新。


2. WidgetKit 与 App Intents #

App Intents 框架提供了一种让你的 App、Widget、Live Activity 等与 Siri、快捷指令、聚焦模式等系统功能集成的方式。

维度WidgetKitApp Intents
作用显示数据接收命令或提供动态内容(如 Siri Shortcuts、交互式 Widget)
示例展示一个任务列表 Widget用户通过 Siri 或点击 Widget 启动特定任务
关系Widget 可以通过绑定 AppIntent 提供交互能力Widget 和 Live Activity 都可与 App Intents 配合,实现深度交互

联系

  • App Intents 可用于定义 Widget 的交互(如点击启动某个功能)。

  • 也可用于配置 Widget 内容(如通过 IntentConfiguration 实现动态筛选)。


总结关系图: #

                   ┌─────────────┐
                   │ App Intents │
                   └────┬────────┘
                        │ 提供交互、启动任务
        ┌───────────────┼─────────────────┐
        │                                   │
┌───────▼─────────┐              ┌─────────▼────────┐
│   WidgetKit      │              │  ActivityKit     │
│  (小组件/信息卡)   │              │ (Live Activity) │
└───────────────┘              └─────────────────┘
  • WidgetKit 是核心 UI 框架。

  • ActivityKit 基于 WidgetKit 实现实时信息展示(Live Activity)。

  • App Intents 提供交互能力,把用户行为与 Widget、Live Activity 连接起来。


如果你想,我也可以为你画一张逻辑图或者构建一个小例子(比如:带有 App Intent 的计时器 Widget + Live Activity)。需要吗?

当然,光看概念确实抽象,我们通过几个具体的 WidgetKit 实际使用例子 来深入理解它的应用场景和机制。这些例子覆盖从静态 Widget 到动态配置、交互、甚至与 ActivityKit 的结合。


🧭 示例 1:展示今天的任务列表(静态小组件) #

场景: #

你有一个 To-Do App,想在主屏幕展示用户今天的任务摘要。

特点: #

  • 静态 Widget:展示固定数据,不能互动。

  • 时间线刷新:例如每小时刷新。

关键代码片段: #

struct TaskEntry: TimelineEntry {
    let date: Date
    let tasks: [String]
}

struct TaskProvider: TimelineProvider {
    func placeholder(in context: Context) -> TaskEntry {
        TaskEntry(date: Date(), tasks: ["任务1", "任务2"])
    }

    func getTimeline(in context: Context, completion: @escaping (Timeline<TaskEntry>) -> Void) {
        let entry = TaskEntry(date: Date(), tasks: fetchTodayTasks())
        let timeline = Timeline(entries: [entry], policy: .after(Date().addingTimeInterval(3600)))
        completion(timeline)
    }
}

struct TaskWidget: Widget {
    var body: some WidgetConfiguration {
        StaticConfiguration(kind: "task_widget", provider: TaskProvider()) { entry in
            VStack(alignment: .leading) {
                ForEach(entry.tasks.prefix(3), id: \.self) { task in
                    Text("• \(task)").font(.headline)
                }
            }
            .padding()
        }
        .configurationDisplayName("今日任务")
        .description("展示今日的任务列表")
        .supportedFamilies([.systemSmall, .systemMedium])
    }
}

⏱️ 示例 2:计时器 Live Activity(结合 ActivityKit) #

场景: #

一个 Pomodoro App 在锁屏或灵动岛显示当前倒计时进度。

特点: #

  • 实时更新状态

  • 使用 ActivityKit 创建 LiveActivity<ContentState> 实例

  • UI 依然是用 WidgetKit 渲染

简化结构: #

struct TimerAttributes: ActivityAttributes {
    public struct ContentState: Codable, Hashable {
        var timeRemaining: TimeInterval
    }

    var timerName: String
}

struct TimerLiveActivityView: View {
    let context: ActivityViewContext<TimerAttributes>

    var body: some View {
        VStack {
            Text(context.attributes.timerName)
            Text("\(Int(context.state.timeRemaining)) 秒")
        }
    }
}

启动 Live Activity 示例:

let attributes = TimerAttributes(timerName: "番茄钟")
let contentState = TimerAttributes.ContentState(timeRemaining: 1500)

let activity = try? Activity<TimerAttributes>.request(
    attributes: attributes,
    contentState: contentState,
    pushType: nil
)

🧠 示例 3:动态内容 Widget + App Intents(可选项目) #

场景: #

用户可以选择一个分类,比如“学习”、“工作”,Widget 就展示对应分类的任务。

特点: #

  • 使用 IntentConfiguration

  • 实现自定义的 AppEntity 与 Intent

示例配置: #

struct CategoryIntent: AppEntity {
    var id: String { name }
    var name: String

    static var defaultQuery = CategoryQuery()

    static func getAllEntities(from query: CategoryQuery) async throws -> [CategoryIntent] {
        // 从数据库读取所有分类
    }
}

struct TaskByCategoryWidget: Widget {
    var body: some WidgetConfiguration {
        IntentConfiguration(
            kind: "task_by_category",
            intent: SelectCategoryIntent.self,
            provider: TaskByCategoryProvider()
        ) { entry in
            Text("分类:\(entry.category.name)")
        }
    }
}

☀️ 示例 4:天气 Widget(系统内置风格) #

场景: #

展示用户当前城市的天气和温度。

特点: #

  • 时间线更新频繁(如每小时)

  • 使用 URLSession 获取数据,缓存后展示

系统的“天气”App 就是一个典型的复杂 WidgetKit 应用,还结合了地理定位权限、图标展示等。


🧩 示例 5:交互式 Widget(iOS 17+) #

场景: #

用户点击 Widget 中的“开始计时”按钮,立即在主 App 启动计时器。

特点: #

  • iOS 17 开始支持 Widget 中的交互

  • 使用 AppIntents + Button(intent:)

struct StartTimerIntent: AppIntent {
    static var title: LocalizedStringResource = "开始计时"
    func perform() async throws -> some IntentResult {
        // 触发计时逻辑
        return .result()
    }
}

struct InteractiveWidgetView: View {
    var body: some View {
        VStack {
            Text("00:00")
            Button(intent: StartTimerIntent()) {
                Text("开始计时")
            }
        }
    }
}

总结 #

示例类型技术点
任务列表静态 Widget时间线、VStack UI
计时器Live ActivityActivityKit + WidgetKit
分类筛选动态配置 WidgetAppEntity + IntentConfiguration
天气定时数据更新网络请求 + Timeline
交互式按钮交互式 WidgetiOS 17+, AppIntents

本文共 2213 字,创建于 May 21, 2025
相关标签: Xcode, SwiftUI, ByAI, ChatGPT