AppIntents

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")
        }
    }
}

  • 9
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值