iOS中Widget的构建

2023-05-04  本文已影响0人  MambaYong

什么是widget

iOS Widget是一种可以放置在 iOS 设备主屏幕上的小型应用程序,提供了一个快速访问和浏览信息的方式。 Widget可以显示各种类型的内容,例如天气、日历、媒体播放器、时钟等等。

iOS Widget 的最大特点是可以在主屏幕上快速查看并与应用程序进行交互,而无需打开应用程序。 Widget 需要使用 WidgetKit 框架来创建和管理,WidgetKit提供了各种各样的组件和 API,使得开发者可以在 Widget中实现丰富的功能和交互体验。

本文要实现的Demo效果如下图所示,显示的是当前时间的Widget

新建widget

首先直接新建一个target,因为widget实际上就是一个target,所显示的数据是依赖宿主App的,创建完widgetxcode会帮我们新建好示例代码。

示例代码中有几个类了解才能知道如何正确构建widget

TimelineEntry

这个类是用来给widget提供数据的,我们可以简单理解为提供数据的demo,唯一的要求是必须要有一个表示时间的属性var date: Date { get },这个属性的作用我们稍后解释,定义一个TimelineEntry结构体如下:

struct SimpleEntry: TimelineEntry {
    let date: Date
    var hour : Int {
        Calendar.current.component(.hour, from: self.date)
    }
    var minute: Int {
        Calendar.current.component(.minute, from: self.date)
    }
}

其中hourminute变量用来显示当前时间的小时和分钟。

TimelineProvider

这是一个协议,还是看一段官方的解释:

A type that advises WidgetKit when to update a widget's display.At various times, WidgetKit requests a timeline from the provider. A timeline is an array of objects conforming to <doc:TimelineEntry>. Eachtimeline entry has a date, and you can specify additional propertiesfor displaying the widget.

这个协议告诉WidgetKit什么时候更新widget,就是给WidgetKit提供数据源,数据源就是上面的TimelineEntry实体,当然还包括更新策略也就是在什么时间需要更新,协议里面有几个方法需要实现:

  func placeholder(in context: Context) -> SimpleEntry {
        SimpleEntry(date: Date())
    }

这个方法是提供一个站位视图,因为我们为WidgetKit提供的数据有可能是异步请求的,这时如果添加widget时,数据可能还没准备好,此时我们可以提供一个站位视图,让用户知道大概得widget样子,这里简单的用当前时间初始化了SimpleEntry

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

这个方法是提供静态快照,当我们添加widget时我们需要在widget gallery中提供一个快照。

    func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
        var entries: [SimpleEntry] = []
        let date = Date().zeroSeconds!
        for hourOffset in 0 ..< 60 {
            let entryDate = Calendar.current.date(byAdding: .minute , value: hourOffset, to: date)!
            let entry = SimpleEntry(date: entryDate)
            entries.append(entry)
        }
        let timeline = Timeline(entries: entries, policy: .atEnd)
        completion(timeline)
    }

这个方法是提供一组数据用于显示,这里我们提供了基于当前时间的60组数据,每个entry数据的date间隔一分钟,并放入了一个entries数组里面,并告知了刷新策略是.atEnd,也就是在60组数据显示完后再更新,此时又会基于当前时间提供60组数据,每个entry数据的date值间隔一分钟,循环如此。

可以发现getSnapshotgetTimeline都利用逃逸闭包来提供entry,这表明方法里面可以进行异步的操作,例如可以进行网络请求,在网络请求成功后构建entry在利用闭包返回,而placeholder则没有提供逃逸闭包,所以这里尽量提供简单的数据。

构建view

利用上面的几个类组合起来构建view


struct widgetTimeEntryView : View {
    var entry: Provider.Entry
    var body: some View {
            VStack {
                HStack {
                 Text("时:   " + String(entry.hour))
                        .font(Font.system(size: 30))
                        .foregroundColor(Color.blue)
                        .background(Color.gray)
                 Spacer()
            }
                HStack {
                 Spacer()
                 Text("分:" + String(entry.minute))
                        .font(Font.system(size: 30))
                        .foregroundColor(Color.orange)
                        .background(Color.gray)
            }
                Text(entry.date, style: .timer)
        
        }
            .padding()
    }
}

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

    var body: some WidgetConfiguration {
        StaticConfiguration(kind: kind, provider: Provider()) { entry in
            widgetTimeEntryView(entry: entry)
        }
        .configurationDisplayName("WidgetDemo")
        .description("This is an example widget.")
    }
}

view利用provider提供的entry来显示,下面的kind是唯一标识符,WidgetKitkind来管理widgetStaticConfiguration是一个配置类,这里需要传入kindprovider,在闭包中需要返回entryViewconfigurationDisplayNamedescription是当我们添加时widget显示的名字和描述信息。

总结

本文简单的介绍了iOSwidget的构建,当然widget和宿主之间是可以进行通信的,比如共享数据同时widget也可以和用户完成交互后,利用用户的交互信息在更新状态,widget的使用主要需要明白entery的构建和其中通过provider如何进行流转的。

上一篇 下一篇

猜你喜欢

热点阅读