iOS 18 开放了控制中心(Control Center),允许第三方 App 提供自定义控制组件。这为用户提供了全新的快捷操作入口,也为开发者提供了新的交互场景。
本篇将介绍如何创建、配置和控制中心组件的最佳实践。
1. 控制中心组件概述
与传统 Widget 的区别
| 维度 | 控制中心组件 | 传统 Widget |
|---|---|---|
| 框架 | AppIntents + SwiftUI |
WidgetKit |
| 位置 | 控制中心(下拉/右上角滑出) | 主屏、锁屏、待机模式 |
| 主要用途 | 快速执行操作 | 信息展示 + 轻量交互 |
| 配置方式 | ControlWidget 协议 |
Widget 协议 |
| 数据刷新 | 通过 App Intent 状态 | 通过 Timeline |
| 最低系统 | iOS 18 | iOS 14 |
控制中心组件支持的功能
- 执行任意的
AppIntent(不需要启动 App) - 显示当前状态(开/关、进度等)
- 支持长按展开更多选项
- 可自定义大小:小方格(1×1)或长条形(2×1)
2. 创建第一个控制中心组件
在创建 Widget Extension 时勾选 Include Control,Xcode 会自动生成模板文件。
基本结构
swift
import AppIntents
import SwiftUI
import WidgetKit
struct FlashlightControl: ControlWidget {
static let kind: String = "FlashlightControl"
var body: some ControlWidgetConfiguration {
StaticControlConfiguration(kind: Self.kind) {
ControlWidgetButton(action: ToggleFlashlightIntent()) {
Label("手电筒", systemImage: "flashlight.on.fill")
}
}
.displayName("手电筒")
.description("快速开启或关闭手电筒")
}
}
对应的 AppIntent
swift
struct ToggleFlashlightIntent: AppIntent {
static var title: LocalizedStringResource = "切换手电筒"
func perform() async throws -> some IntentResult {
// 执行实际的操作逻辑
toggleDeviceFlashlight()
return .result()
}
}
3. 有状态的控制组件
控制中心组件可以展示状态(如开/关),需要实现 ControlWidget 的状态相关能力:
使用 Toggle
swift
struct WiFiControl: ControlWidget {
var body: some ControlWidgetConfiguration {
StaticControlConfiguration(kind: "WiFiControl") {
ControlWidgetToggle(isOn: WiFiState.shared.$isEnabled, action: ToggleWiFiIntent()) {
Label("Wi-Fi", systemImage: "wifi")
}
}
.displayName("Wi-Fi")
}
}
// 状态管理
@Observable class WiFiState {
static let shared = WiFiState()
var isEnabled = true
}
自定义状态的 Button
swift
struct VPNControl: ControlWidget {
var body: some ControlWidgetConfiguration {
StaticControlConfiguration(kind: "VPNControl") {
ControlWidgetButton(action: ToggleVPNIntent()) { isRunning in
if isRunning {
Label("已连接", systemImage: "lock.shield.fill")
.foregroundColor(.green)
} else {
Label("未连接", systemImage: "lock.shield")
.foregroundColor(.secondary)
}
}
}
.displayName("VPN")
}
}
4. 多种控制大小
swift
struct MusicControl: ControlWidget {
var body: some ControlWidgetConfiguration {
StaticControlConfiguration(kind: "MusicControl") {
// 小方格(1×1)
ControlWidgetButton(action: PlayPauseIntent()) {
Label("播放", systemImage: "play.fill")
}
// 长条形(2×1)包含更多按钮
ControlWidgetButton(action: PlayPauseIntent()) {
HStack {
Label("上一首", systemImage: "backward.fill")
Label("播放", systemImage: "play.fill")
.font(.title)
Label("下一首", systemImage: "forward.fill")
}
}
}
.displayName("音乐")
.supportedControlFamilies([.controlSmall, .controlLarge])
}
}
5. 注册到 Control Center
在 Widget Bundle 中注册:
swift
@main
struct MyWidgetBundle: WidgetBundle {
var body: some Widget {
// 传统 Widget
MainWidget()
// 控制中心组件
FlashlightControl()
WiFiControl()
VPNControl()
}
}
用户可以在控制中心编辑模式下添加这些组件。
6. 控制中心组件与 App Intent 的数据共享
控制组件和 Widget 使用相同的数据共享机制:
swift
struct SaveNoteIntent: AppIntent {
static var title: LocalizedStringResource = "快速记录"
@Parameter(title: "内容")
var content: String
init() { content = "" }
init(content: String) { self.content = content }
func perform() async throws -> some IntentResult {
// 写入共享容器
let defaults = UserDefaults(suiteName: "group.com.example.app")
var notes = defaults?.stringArray(forKey: "quick_notes") ?? []
notes.append(content)
defaults?.set(notes, forKey: "quick_notes")
return .result()
}
}
7. 最佳实践
- 操作要快:控制中心的操作应即时完成(< 1 秒),复杂的异步操作应在后台完成
- 状态要准:如果展示状态(如开关),确保状态与实际同步。使用 App Group 共享状态数据
- 图标要清晰:使用 SF Symbols,确保在控制中心的小图标尺寸下仍然可辨识
- 避免敏感操作:控制中心组件无需解锁即可使用,避免暴露敏感功能(如支付、查看隐私信息等)
- 提供反馈:通过系统震动(Haptics)或短暂显示状态变化来提供操作反馈
8. 常见问题
Q: 控制中心组件可以和传统 Widget 共存吗?
A: 可以。它们都在同一个 Widget Extension 中,通过 WidgetBundle 统一注册。
Q: 控制中心组件能展示动态数据吗?
A: 可以展示基于 AppIntent 执行结果的状态变化,但不能实现类似 Widget Timeline 的自动刷新。
Q: 是否支持用户自定义控制中心组件的大小?
A: 用户可以像排列主屏 Widget 一样拖动调整大小,但目前主要支持小和中等两种。
Q: 与快捷指令(Shortcuts)有什么区别?
A: 控制中心组件更轻量、无需 Siri 识别、始终在控制中心可用;快捷指令功能更强大、支持复杂自动化。
小结
- iOS 18 的控制中心组件为 App 提供了全新的快捷交互通道
- 使用
ControlWidget协议和ControlWidgetButton/ControlWidgetToggle构建 - 核心能力依赖于 App Intents 框架
- 适合快速操作、状态切换、一键触发等场景
最后,希望这篇文章能帮到有需要的朋友,如果觉得有帮助,点个赞、加个关注,笔者也会继续努力输出更多优质内容。
上一篇 :iOS Widget 开发-13:Live Activity 实战详解
下一篇 :iOS Widget 开发-15:Widget 性能优化指南