SwiftUI创建Widget小组件一

174 阅读3分钟
  1. Widget是iOS 14的新特性,要创建小组件,需要使用到SwiftUIQ和WidgetKit。要在项目中创建 Widget,首先点击此处的加号图标,添加一个target。

image.png

  1. 点击右侧的垂直滚动条,查看Widget扩展所在的位置。

image.png

  1. 选择此处的Widget Extension模板。

image.png

  1. 点击下一步,进入下一步设置页面。

image.png

  1. 输入Product Name。

image.png

  1. 取消勾选此处的复选框。如果Widget提供了用户可配置的属性,请勾选此处的选项。我们将在后面创建用户可配置的Widget。

image.png

  1. 点击完成按钮,完成Target创建。

image.png

  1. 点击激活按钮,激活Widget的scheme。这样当点击编译并运行按钮时,可以在模拟器中运行该 Widget。

image.png

  1. 点击此处箭头,显示Widget相关文件。

image.png

  1. 与Widget相关的文件都在这个文件夹里面。

image.png

  1. Provider是Widget的核心引擎。它负责向小组件提供数据、设置更新数据的时间间隔、设置在 Widget加载时显示的占位符视图,以及设置位于Widget库中的快照。

image.png

  1. 时间线功能用于创建一个或多个Entry。可以设置时间间隔,之后需要更新TimelineEntry。 SimpleEntry用来保存单个TimelineEntry数据,并最终显示在Widget上。

image.png

  1. Widget的内容设置在DemoWidgetEntryView的内部。@main属性表示DemoWidget是Widget的入口。

image.png

  1. kind是用于在Widget库中,将Widget与其他Widget区分开的标识符。StaticConfiguration表示不需要用户配置属性的Widget。例如,显示一般市场信息的股市Widget。

image.png

  1. 应用程序启动之后,在主屏幕上显示了刚刚创建的Widget,它显示了应用启动时的时间。我们可以添加不同尺寸的Widget,首先长按打开选项菜单。

image.png

  1. 选择此处菜单,使主屏幕进入编辑模式。

image.png

  1. 点击左上角+号按钮,打开小组件列表。

image.png

  1. 然后选择新创建的小组件。

image.png

  1. 在此处按下并向左侧拖动,显示中型尺寸的小组件。

image.png

  1. 点击此处的添加小组件按钮,往主屏幕添加一个中型尺寸的小组件。

image.png

  1. 此时在主屏幕上显示了两个不同尺寸的小组件,点击右上角的完成按钮,完成对主屏幕的编辑。

image.png

  1. 这样就创建了一个简单的小组件,我们将在下一节对项目进行修改,以创建更加强大的小组件。

image.png

源码:

import WidgetKit
import SwiftUI
import Intents

struct Provider: IntentTimelineProvider {
    func placeholder(in context: Context) -> SimpleEntry {
        SimpleEntry(date: Date(), configuration: ConfigurationIntent())
    }

    func getSnapshot(for configuration: ConfigurationIntent, in context: Context, completion: @escaping (SimpleEntry) -> ()) {
        let entry = SimpleEntry(date: Date(), configuration: configuration)
        completion(entry)
    }

    func getTimeline(for configuration: ConfigurationIntent, in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
        var entries: [SimpleEntry] = []

        // Generate a timeline consisting of five entries an hour apart, starting from the current date.
        let currentDate = Date()
        for hourOffset in 0 ..< 5 {
            let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: currentDate)!
            let entry = SimpleEntry(date: entryDate, configuration: configuration)
            entries.append(entry)
        }

        let timeline = Timeline(entries: entries, policy: .atEnd)
        completion(timeline)
    }
}

struct SimpleEntry: TimelineEntry {
    let date: Date
    let configuration: ConfigurationIntent
}

struct DemoWidgetEntryView : View {
    var entry: Provider.Entry

    var body: some View {
        Text(entry.date, style: .time)
    }
}

@main
struct DemoWidget: Widget {
    let kind: String = "DemoWidget"

    var body: some WidgetConfiguration {
        IntentConfiguration(kind: kind, intent: ConfigurationIntent.self, provider: Provider()) { entry in
            DemoWidgetEntryView(entry: entry)
        }
        .configurationDisplayName("My Widget")
        .description("This is an example widget.")
    }
}

struct DemoWidget_Previews: PreviewProvider {
    static var previews: some View {
        DemoWidgetEntryView(entry: SimpleEntry(date: Date(),
                    configuration: ConfigurationIntent()))
            .previewContext(WidgetPreviewContext(family: .systemSmall))
            .previewDisplayName("Small widget")
    }
}