1. AppIntents基础知识
1. 支持版本,iOS 17 +
2. 有两个用处
2.1 用于组件内交互,目前仅支持Button、Toggle,两种SwiftUI组件
2.2 用于小组件编辑,替代Intents Extension。
2. AppIntents代码组成
2.1 用于编辑小组件,整个Widget组成
1. Entry,与Widget Extension一样
2. Provider,这里需要遵循AppIntentTimelineProvider协议
3. View,与Widget Extension一样
4. AppIntent, 遵循AppIntent协议的结构体(这里用WidgetConfigurationIntent,WidgetConfigurationIntent遵循这AppIntent协议)
5. Widget,遵循Widget协议结构体,用于整合Entry,Provider,View,AppIntent。使用AppIntentConfiguration....结构体进行整合
2.2 用于组件内交互,基于上面2.1
1. 遵循AppIntent协议结构体
2. 结构体内部,实现perform方法,处理点击
3. AppIntents代码实现,同时具备交互与编辑能力
import AppIntents
import SwiftUI
import WidgetKit
/// 点击交互用AppIntent
@available(iOS 17.0, *)
struct ButtonIntent: AppIntent {
static var title: LocalizedStringResource = "button press"
static var description: IntentDescription? = IntentDescription(stringLiteral: "none")
@Parameter(title: "edit message")
var widgetEdit: String?
init() { }
init(widgetEdit: String? = "none") {
self.widgetEdit = widgetEdit
}
func perform() async throws -> some IntentResult {
print("小组件编辑: \(widgetEdit ?? "none")")
return .result()
}
}
/// 用于配置小组件编辑用AppIntent
@available(iOS 17.0, *)
struct ConfigurationIntent: WidgetConfigurationIntent {
static var title: LocalizedStringResource = "个性化设置"
static var description: IntentDescription? = IntentDescription(stringLiteral: "背景配置")
@Parameter(title: "小组件背景")
var bgColor: AppIntentsColor?
//用于编辑弹窗显示哪几项 @Parameter, 在系统编辑栏这里只配置了颜色
static var parameterSummary: some ParameterSummary {
Summary {
\.$bgColor
}
}
//============================小组件背景类型============================
struct AppIntentsColor: AppEntity, Identifiable {
static let typeDisplayRepresentation = TypeDisplayRepresentation(name: "color entity")
static let defaultQuery = AppIntentsColorQuery()
let id: String
let display: String //标题
var displayRepresentation: DisplayRepresentation {
.init(title: "\(display)")
}
init(identifier: String, display: String) {
self.id = identifier
self.display = display
}
}
struct AppIntentsColorQuery: EntityStringQuery {
let colors: [AppIntentsColor] = [
AppIntentsColor(identifier: "dark", display: "黑色"),
AppIntentsColor(identifier: "light", display: "白色")
]
func entities(matching string: String) async throws -> [AppIntentsColor] {
colors.filter { String($0.display.lowercased()).contains(string.lowercased()) }
}
func entities(for identifiers: [String]) async throws -> [AppIntentsColor] {
colors.filter { identifiers.contains($0.id) }
}
func suggestedEntities() async throws -> [AppIntentsColor] {
colors
}
func defaultResult() async -> AppIntentsColor? {
colors.last
}
}
//==============================================================
}
///Entry
@available(iOS 17.0, *)
struct AppIntentsEntry: TimelineEntry {
var date: Date
var editMessage: String?
}
///Provider
@available(iOS 17.0, *)
struct AppIntentsProvider: AppIntentTimelineProvider {
typealias Entry = AppIntentsEntry
typealias Intent = ConfigurationIntent
func placeholder(in context: Context) -> Entry {
Entry(date: Date(), editMessage: "none")
}
func snapshot(for configuration: Intent, in context: Context) async -> Entry {
Entry(date: Date(), editMessage: "none")
}
func timeline(for configuration: Intent, in context: Context) async -> Timeline<Entry> {
// configuration.bgColor 这里可以获取到编辑的参数
let entry = Entry(date: Date(), editMessage: configuration.bgColor?.display ?? "none")
return Timeline(entries: [entry], policy: .never)
}
}
/// View
@available(iOS 17.0, *)
struct AppIntentsView: View {
let entry: AppIntentsEntry
var body: some View {
VStack(spacing: 10) {
Toggle("toggle 当前编辑", isOn: false, intent: ButtonIntent(widgetEdit: entry.editMessage))
.frame(height: 44)
.background(Color.red)
Button("button 当前编辑", intent: ButtonIntent(widgetEdit: entry.editMessage))
.frame(height: 44)
.background(Color.red)
}
}
}
/// 整合 AppIntent | Provider | Entry | View, 输出widget
@available(iOS 17.0, *)
struct AppIntentsWidget: Widget {
var body: some WidgetConfiguration {
AppIntentConfiguration(kind: "appIntents.kind", intent: ConfigurationIntent.self, provider: AppIntentsProvider()) { entry in
AppIntentsView(entry: entry)
.containerBackground(Color.clear, for: .widget)
}
.configurationDisplayName("My Widget")
.description("This is an example widget.")
.supportedFamilies([.systemSmall,.systemMedium])
}
}
4. Toggle、Button,在Widget中一些简单的应用
struct widgetEntryView : View {
var entry: Provider.Entry
var body: some View {
VStack(spacing: 10) {
if #available(iOS 17.0, *) {
Text("toggle|button点击闪烁")
.invalidatableContent()
HStack(spacing: 20) {
Toggle("", isOn: false, intent: TestIntent())
.toggleStyle(TestToggleStyle())
Button("", intent: TestIntent())
.buttonStyle(TestButtonStyle())
Button(intent: TestIntent()) {
Image(systemName: "magnifyingglass")
}
.buttonStyle(.borderless)
}
}
}
}
}
struct TestToggleStyle: ToggleStyle {
func makeBody(configuration: Configuration) -> some View {
if configuration.isOn {
Image(systemName: "house")
}else {
Image(systemName: "house.fill")
}
}
}
struct TestButtonStyle: ButtonStyle {
func makeBody(configuration: Configuration) -> some View {
if configuration.isPressed {
Image(systemName: "person")
}else {
Image(systemName: "person.fill")
}
}
}