美文网首页
iOS Widget开发1:创建一个Widget Extensi

iOS Widget开发1:创建一个Widget Extensi

作者: 烽火连天x | 来源:发表于2020-07-10 18:16 被阅读0次

    了解Widget

    官方学习WidgetKit Demo
    Widgets显示相关的、可浏览的内容,允许用户快速访问你的App以获取更多详细信息。你的App可以提供多种小组件,让用户专注于对他们最重要的信息。
    向你的应用添加一个小组件需要少量的设置,以及一些关于你的用户界面的配置和风格的决定。小组件使用SwiftUI视图显示其内容。有关详细信息,请参见SwiftUI

    添加一个Widget到你的App

    Widget Extension模板为创建小组件提供了一个起点。一个Widget Extension可以包含多种类型的小组件。例如,一个体育应用程序可能有一个小组件显示团队信息,另一个小组件显示比赛日程,这个例子一个Widget Extension包含了两个组件。建议在一个Widget Extension中包含你的App所有小组件。
    添加步骤如下:

    1. 在Xcode中打开你的项目,然后选择 File > New > Target 。
    2. 从“Application Extension”组中,选择“Widget Extension”,然后单击“Next”。如下图:


      1.png
    3. 然后,给小组件命令,如下:


      2.png
    4. 如果小组件提供用户可配置的属性,请选中include configuration intent复选框。
    5. 点击Finish,会生成你们组件文件,如:AppWidget.swift、AppWidget.intentdefinition、Assets.xcassets、Info.plist 。如下图:


      3.png

    然后你可以运行到iOS14的设备上看效果,会看到默认的小时钟组件。


    IMG_0039.PNG

    配置描述

    widget extension模板提供了一个符合widget协议的初始widget实现。此小组件的body属性决定小组件是否具有用户可配置的属性。有两种配置:

    • StaticConfiguration:对于没有用户可配置属性的小组件。例如,显示一般市场信息的股市小组件,或显示趋势标题的新闻小组件。
    • IntentConfiguration:对于具有用户可配置属性的小组件。你可以使用SiriKit自定义内容来定义属性。例如,需要一个城市的邮政编码的天气小组件,或者需要跟踪号码的包裹跟踪小组件。
      要初始化配置,请提供以下信息:
    1. Kind: 标识小部件的字符串。这是一个你选择的标识符,应该描述小部件所代表的内容。
    2. Provider:一个符合TimelineProvider的对象,它生成一个时间轴,告诉WidgetKit何时呈现小组件。时间线包含您定义的自定义TimelineEntry类型。时间线条目标识您希望WidgetKit更新小组件内容的日期。包括小组件视图需要在自定义类型中呈现的属性。
    3. Placeholder View: WidgetKit第一次使用SwiftUI视图呈现小组件。占位符是小组件的通用表示,没有特定的配置或数据。
    4. Content Closure: 包含SwiftUI视图的闭包。WidgetKit调用它来呈现小组件的内容,从提供者传递一个TimelineEntry参数。
    5. Custom Intent: 定义用户可配置属性的自定义意图。有关添加自定义更多信息,请参阅 Making a Configurable Widget
      例如下面代码显示IntentConfiguration类型的组件:
    @main
    struct AppWidget: Widget {
        private let kind: String = "AppWidget" //小组件的标识
    
        public var body: some WidgetConfiguration {
            IntentConfiguration(kind: kind, intent: ConfigurationIntent.self, provider: Provider(), placeholder: PlaceholderView()) { entry in
                AppWidgetEntryView(entry: entry)
            }
            .configurationDisplayName("My Widget") //小组件的名称
            .description("This is an example widget.") //小组件的描述
            .supportedFamilies([.systemSmall, .systemMedium, .systemLarge]) //用户选择小部件、中版本或大版本的组件
        }
    }
    

    在上面代码中,小组件使用PlaceholderView()作为占位符视图,并在内容闭包中使用AppWidgetEntryView。占位符视图显示小组件的通用表示,让用户大致了解小部件显示的内容。不要在占位符视图中包含实际数据。例如,使用灰色框表示文本行,或使用灰色圆表示图像。
    Provider为小组件生成一个时间轴,当每个时间轴条目的日期到达时,WidgetKit调用content闭包来更新显示小组件的内容。
    注意这个小组件上@main属性的用法。此属性指示AppWidget是小组件扩展的入口点,表示该扩展包含一个小组件。

    TimelineProvider

    TimelineEntry为TimelineProvider提供数据信息来源,如下所示:

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

    为了在窗口小组件库中显示小组件,WidgetKit要求提供者提供预览快照。你可以通过检查此 snapshot(for:with:completion:)方法中context的isPreview属性来判断小组件显示情况。当isPreview为true时,WidgetKit会在widget库中显示你的widget。对于有网络数据的话,你需要先提供一个默认数据显示快照。如下示例代码:

    struct Provider: IntentTimelineProvider {
        public func snapshot(for configuration: ConfigurationIntent, with context: Context, completion: @escaping (SimpleEntry) -> ()) {
            print(context.isPreview) //显示widget的显示情况
            let entry = SimpleEntry(date: Date(), configuration: configuration)
            completion(entry)
        }
    }
    

    WidgetKit框架要求我们用timeline(for:with:completion:)来控制刷新小组件的时间。

    struct Provider: IntentTimelineProvider {
        public func snapshot(for configuration: ConfigurationIntent, with context: Context, completion: @escaping (SimpleEntry) -> ()) {
            print(context.isPreview) //显示widget的显示情况
            let entry = SimpleEntry(date: Date(), configuration: configuration)
            completion(entry)
        }
    
        public func timeline(for configuration: ConfigurationIntent, with 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)
            }
    
            // Create the timeline with the entry and a reload policy with the date
            // for the next update.
            let timeline = Timeline(entries: entries, policy: .atEnd)
            // Call the completion to pass the timeline to WidgetKit.
            completion(timeline)
        }
    }
    

    小组件的显示内容

    小组件UI使用SwiftUI来编写的,当用户从widget库中添加你的widget时,他们会从widget支持的组件中选择特定的组件(小型、中型或大型),widget的内容闭包必须能够呈现widget支持的每个组件。根据组件类型可以不同的实现,代码示例如下:

    struct AppWidgetEntryView : View {
        @Environment(\.widgetFamily) var family: WidgetFamily
        var entry: Provider.Entry
        
        //view使用@ViewBuilder声明,因为它使用的view类型不同。
        @ViewBuilder
        var body: some View {
            switch family {
            case .systemSmall:
                Text(entry.date, style: .time)
            case .systemMedium:
                Text(entry.date, style: .time)
            case .systemLarge:
                Text(entry.date, style: .time)
            default:
                Text(entry.date, style: .time)
            }
        }
    }
    

    小组件显示只读信息,不支持交互元素,如滚动元素或开关。

    在一个Widget Extension创建多个小组件

    要支持多个小组件,需要声明一个符合WidgetBundle的结构,WidgetBundle在其body属性中将多个小组件组合在一起。在这个Widget bundle结构上添加@main属性,告诉WidgetKit你的扩展支持多个widget。代码示例:

    @main
    struct AppWidgets: WidgetBundle {
        @WidgetBundleBuilder
        var body: some Widget {
            AppWidget()
            //可以继续添加其它Widget
        }
    }
    

    相关文章

      网友评论

          本文标题:iOS Widget开发1:创建一个Widget Extensi

          本文链接:https://www.haomeiwen.com/subject/miopcktx.html