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

相关推荐
for_ever_love__12 小时前
UI学习:UICollectionView瀑布流
学习·ui·ios·objective-c·cocoa
大熊猫侯佩16 小时前
WWDC26 全网首发:SwiftUI 8 “可重排序“操作符深度解析
ios·swiftui·swift
邓小乐17 小时前
Workaround: Xcode27 下载iOS 27.0 Simulator
ios·xcode
韩曙亮17 小时前
【Flutter】Flutter 中的 Android / iOS 特殊配置 ① ( 网络权限配置 | HTTP 明文传输配置 | 应用名称配置 )
android·网络·flutter·http·ios·网络权限
人月神话-Lee19 小时前
【图像处理】颜色空间——RGB之外的世界
图像处理·人工智能·ios·ai编程·swift·rgb·颜色空间
东坡肘子20 小时前
WWDC 2026 初印象:符合预期,但更务实 -- 肘子的 Swift 周报 #139
人工智能·swiftui·swift
CocoaKier20 小时前
苹果后台年龄分级填写错误,可能导致审核被拒!
ios·apple
月诸清酒20 小时前
Codex 现在能在浏览器里跑 iOS 模拟器了
ios
武子康21 小时前
调查研究-159 Apple WWDC 2026 定档 6/8-12:Siri 与 AI 升级,可能是苹果最关键的一次
人工智能·深度学习·ios·ai·chatgpt·apple·wwdc