什么是widget
iOS Widget
是一种可以放置在 iOS
设备主屏幕上的小型应用程序,提供了一个快速访问和浏览信息的方式。 Widget
可以显示各种类型的内容,例如天气、日历、媒体播放器、时钟等等。
iOS Widget
的最大特点是可以在主屏幕上快速查看并与应用程序进行交互,而无需打开应用程序。 Widget 需要使用 WidgetKit 框架来创建和管理,WidgetKit
提供了各种各样的组件和 API
,使得开发者可以在 Widget
中实现丰富的功能和交互体验。
本文要实现的Demo
效果如下图所示,显示的是当前时间的Widget
。
新建widget
首先直接新建一个target
,因为widget
实际上就是一个target
,所显示的数据是依赖宿主App
的,创建完widget
后xcode
会帮我们新建好示例代码。
示例代码中有几个类了解才能知道如何正确构建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)
}
}
其中hour
和minute
变量用来显示当前时间的小时和分钟。
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
值间隔一分钟,循环如此。
可以发现
getSnapshot
和getTimeline
都利用逃逸闭包来提供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
是唯一标识符,WidgetKit
用kind
来管理widget
,StaticConfiguration
是一个配置类,这里需要传入kind
和provider
,在闭包中需要返回entryView
,configurationDisplayName
和description
是当我们添加时widget
显示的名字和描述信息。
总结
本文简单的介绍了iOS
中widget
的构建,当然widget
和宿主之间是可以进行通信的,比如共享数据同时widget
也可以和用户完成交互后,利用用户的交互信息在更新状态,widget
的使用主要需要明白entery
的构建和其中通过provider
如何进行流转的。
网友评论