iOS Widget 开发-14:iOS 18 控制中心组件开发

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 性能优化指南

相关推荐
七牛云行业应用3 小时前
OpenAI Codex手机版上线实战:iOS/Android 5步配置远程控制指南(2026)
android·ios·智能手机
sakiko_3 小时前
Swift学习笔记29-数据库SQlite
数据库·学习·sqlite·swift
2501_915921435 小时前
使用Swift和Xcode创建简单iOS应用完整教程
ide·vscode·ios·个人开发·xcode·swift·敏捷流程
库奇噜啦呼5 小时前
【iOS】Spotify项目总结
ios·iphone
sakiko_19 小时前
Swift学习笔记28-缓存
笔记·学习·swift
鹤卿1231 天前
OC UI ——UIGestureRecognizer 手势识别
ui·ios·objective-c
hhb_6181 天前
Swift技术难点梳理与实战案例解析
开发语言·ios·swift
MonkeyKing1 天前
iOS UICollectionView 高可用架构:复用、预加载、横向嵌套实战详解
ios