iOS17适配指南

iOS17适配指南之Widget

2023-08-20  本文已影响0人  YungFan

介绍

extension Button {
    public init<I: AppIntent>(
        intent: I,
        @ViewBuilder label: () -> Label
    )
}

extension Toggle {
    public init<I: AppIntent>(
        isOn: Bool,
        intent: I,
        @ViewBuilder label: () -> Label
    )
}

案例

效果

效果图.gif

实现

import AppIntents
import Foundation
import SwiftUI
import WidgetKit

// MARK: - Model
class Counter {
    @AppStorage("count", store: UserDefaults(suiteName: "Widget2023")) static var count = 0

    static func incrementCount() {
        count += 1
    }

    static func decrementCount() {
        count -= 1
    }

    static func currentCount() -> Int {
        return count
    }
}



// MARK: - AppIntent
struct CountIntent: AppIntent {
    static var title: LocalizedStringResource = "CountIntent"
    static var description: IntentDescription = IntentDescription("CountIntent")

    // AppIntent的输入参数
    @Parameter(title: "isIncrement")
    var isIncrement: Bool

    init() {
    }

    init(isIncrement: Bool) {
        self.isIncrement = isIncrement
    }

    func perform() async throws -> some IntentResult {
        if isIncrement {
            Counter.incrementCount()
        } else {
            Counter.decrementCount()
        }
        return .result()
    }
}



// 宿主App
struct ContentView: View {
    @Environment(\.scenePhase) private var phase
    @State private var count = 0

    var body: some View {
        VStack {
            Text("Count: \(count)")
                .font(.largeTitle)
                .foregroundStyle(.primary)

            HStack {
                Button {
                    count += 1
                    Counter.incrementCount()
                    WidgetCenter.shared.reloadAllTimelines()
                } label: {
                    Image(systemName: "plus")
                        .font(.largeTitle)
                }

                Button {
                    count -= 1
                    Counter.decrementCount()
                    WidgetCenter.shared.reloadAllTimelines()
                } label: {
                    Image(systemName: "minus")
                        .font(.largeTitle)
                }
            }
        }
        .padding()
        .onChange(of: phase) {
            count = Counter.currentCount()
        }
    }
}



// MARK: - Widget
struct Provider: TimelineProvider {
    func placeholder(in context: Context) -> SimpleEntry {
        SimpleEntry(date: Date(), count: "\(Counter.currentCount())")
    }

    func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -> Void) {
        let entry = SimpleEntry(date: Date(), count: "\(Counter.currentCount())")
        completion(entry)
    }

    func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> Void) {
        let timeline = Timeline(entries: [SimpleEntry(date: Date(), count: "\(Counter.currentCount())")], policy: .atEnd)
        completion(timeline)
    }
}

struct SimpleEntry: TimelineEntry {
    let date: Date
    let count: String
}

struct CountWidgetEntryView: View {
    // iOS17新增环境变量,设置边距
    @Environment(\.widgetContentMargins) var margins
    var entry: Provider.Entry

    var body: some View {
        VStack {
            Text("Count: \(entry.count)")

            HStack {
                // 交互
                Button(intent: CountIntent(isIncrement: true)) {
                    Image(systemName: "plus.circle")
                }

                Button(intent: CountIntent(isIncrement: false)) {
                    Image(systemName: "minus.circle")
                }
            }
            .font(.largeTitle)
        }
        .containerBackground(.fill.tertiary, for: .widget) // iOS17新增,设置小组件背景
        .padding(.top, margins.top) // 设置顶部边距
    }
}

struct CountWidget: Widget {
    let kind: String = "CountWidget"

    var body: some WidgetConfiguration {
        StaticConfiguration(kind: kind, provider: Provider()) { entry in
            CountWidgetEntryView(entry: entry)
        }
        .configurationDisplayName("CountWidget")
        .description("This is a CountWidget.")
    }
}

// MARK: - 预览
#Preview(as: .systemSmall) {
    CountWidget()
} timeline: {
    SimpleEntry(date: .now, count: "99")
}

#Preview(as: .systemMedium) {
    CountWidget()
} timeline: {
    SimpleEntry(date: .now, count: "99")
}

#Preview(as: .systemLarge) {
    CountWidget()
} timeline: {
    SimpleEntry(date: .now, count: "99")
}
上一篇下一篇

猜你喜欢

热点阅读