Widgets 能够显示你 App 相关的内容,使用户能够快速访问您的应用以获取更多详细的信息;一个 iOS App 能够提供多种样式的 Widget ,使用户能够专一于那些对本身最有价值的信息;咱们能够添加同一 Widget 的多个副本,从而根据其独特的需求和布局定制每一个 Widget;若是 Widget 中有自定义的功能,则用户能够分别个性化 Widget;Widget 支持多种尺寸,你能够根据实际状况选择适合本身的尺寸,在屏幕可用空间有限的状况下,Widget 呈现的信息将是用户最关心的。api
将 Widget 添加到 App 中须要进行少许的设置,而且将使用 SwiftUI 来展现他的内容。bash
Widget extension 模板提供了符合 Widget 协议的初始化实现。Widget 体里面的属性肯定 了 Widget 是否具备用户可配置的属性。服务器
有两种配置:微信
StaticConfiguration:对于没有用户可配置属性的 Widget。例如,显示通常市场信息的股市 Widget,或显示趋势头条的新闻 Widget。异步
IntentConfiguration:用于具备用户可配置属性的 Widget。例如,须要一个城市的邮政编码的天气 Widget,或者须要一个跟踪号的包裹跟踪 Widget。ide
Include Configuration Intent 复选框决定了 Xcode 使用哪一种配置。当您选中此复选框时,Xcode 将使用 intent configuration ;不然,它使用静态配置。要初始化配置,请提供如下信息:布局
如下代码显示了一个 Widget,它为游戏提供了常规的,不可配置的状态:ui
@main
struct GameStatusWidget: Widget {
var body: some WidgetConfiguration {
StaticConfiguration(
kind: "com.mygame.game-status",
provider: GameStatusProvider(),
placeholder: GameStatusPlaceholderView()
) { entry in
GameStatusView(entry.gameStatus)
}
.configurationDisplayName("Game Status")
.description("Shows an overview of your game status")
.supportedFamilies([.systemSmall, .systemMedium, .systemLarge])
}
}
复制代码
在此示例中,Widget 将 GameStatusPlaceholder 用于placeholder view (这里简称占位符视图),并将 GameStatusView 用于 content closure。占位符视图显示您 Widget 的通常表示形式,使用户能够大体了解 Widget 的显示内容。不要在占位符视图中包含实际数据。例如,使用灰色框表示文本行,或使用灰色圆圈表示图像。编码
Provider 为 Widget 生成 timeline,并在每一个条目中包含游戏状态详细信息, 每一个 timeline 条目的日期到达时,WidgetKit 都会调用 content closure 以显示 widget 的内容。最后,修饰符指定 Widget 库中显示的名称和描述,并容许用户选择小,中或大版本的 Widget。spa
请注意此 Widget 上 @main 属性的用法。此属性指示 GameStatusWidget 是窗口小部件扩展的入口点,这意味着该扩展包含单个 Widget, 要支持多个小部件,请参阅在App Extension中声明多个小部件。
Timeline provider 会生成一个由时间线条目组成的时间线,每一个条目都指定更新 Widget 内容的日期和时间。游戏状态 Widget 可能会定义其时间轴条目,以包含表明游戏状态的字符串,以下所示:
struct GameStatusEntry: TimelineEntry {
var date: Date
var gameStatus: String
}
复制代码
为了在 Widget 库中显示,WidgetKit 要求提供者提供预览快照。
您能够经过检查传递给 snapshot(for:with:completion :) 方法的 context 的 isPreview 属性来标识此预览请求。当 isPreview 为 true 时,Widget 将在 WidgetKit 库中显示。做为响应,您须要快速建立预览快照。若是您的 Widget 须要花费时间才能从服务器生成或从服务器获取的资源或信息,可使用以下示例代码:
struct GameStatusProvider: TimelineProvider {
var hasFetchedGameStatus: Bool
var gameStatusFromServer: String
func snapshot(with context: Context, completion: @escaping (Entry) -> ()) {
let date = Date()
let entry: GameStatusEntry
if context.isPreview && !hasFetchedGameStatus {
entry = GameStatusEntry(date: date, gameStatus: "—")
} else {
entry = GameStatusEntry(date: date, gameStatus: gameStatusFromServer)
}
completion(entry)
}
复制代码
请求初始 snapshot 后,WidgetKit调用时间轴(for:with:completion :) 来向 provider 请求常规时间轴。时间轴由一个或多个时间轴条目以及一个重载策略组成,该重载策略通知 WidgetKit 什么时候请求后续时间轴。
如下示例显示了游戏状态 widget 的 provider 如何生成时间线,该时间线由服务器上具备当前游戏状态的单个条目以及重载策略组成,以在15分钟内请求新的时间线:
struct GameStatusProvider: TimelineProvider {
func timeline(with context: Context, completion: @escaping (Timeline<GameStatusEntry>) -> ()) {
// Create a timeline entry for "now."
let date = Date()
let entry = GameStatusEntry(
date: date,
gameStatus: gameStatusFromServer
)
// Create a date that's 15 minutes in the future. let nextUpdateDate = Calendar.current.date(byAdding: .minute, value: 15, to: date)! // Create the timeline with the entry and a reload policy with the date // for the next update. let timeline = Timeline( entries:[entry], policy: .after(nextUpdateDate) ) // Call the completion to pass the timeline to WidgetKit. completion(timeline) } } 复制代码
在此示例中,若是 Widget 不具备服务器的当前状态,则它能够存储完成的引用,向服务器执行异步请求以获取游戏状态,并在该请求完成时调用完成。
Widget 一般经过组合使用 SwiftUI 视图定义内容。
当用户从 Widget 库中添加 Widget 时,他们从 Widget 支持的类型中选择特定的系列(小,中或大),Widget 的 content closure 必须可以渲染其支持的每一个类型, WidgetKit 在 SwiftUI environment 中设置相应的系列和其余属性,例如配色方案(浅色或深色)。
在上面显示的游戏状态 Widget 的配置中,content closure 使用 GameStatusView 来显示状态。由于 Widget 支持全部三个小部件系列,因此它使用 widgetFamily 决定显示哪一个特定的 SwiftUI 视图,以下所示:
struct GameStatusView : View {
@Environment(\.widgetFamily) var family: WidgetFamily
var gameStatus: GameStatus
@ViewBuilder
var body: some View {
switch family {
case .systemSmall: GameTurnSummary(gameStatus)
case .systemMedium: GameStatusWithLastTurnResult(gameStatus)
case .systemLarge: GameStatusWithStatistics(gameStatus)
default: GameDetailsNotAvailable()
}
}
}
复制代码
Widget 仅显示只读信息,不支持交互元素,例如滚动元素或开关。在呈现 Widget 的内容时,WidgetKit 会忽略交互式元素。
当用户与您的 Widget 交互时,WidgetKit 会激活您的应用程序,并传递您指定的URL, 当您的应用激活时,经过将用户带到相关位置来处理 URL。
例如,若是游戏应用程序具备第二个用于显示角色健康情况的小部件,而第三个用于显示排行榜,则将它们分组在一块儿,以下所示:
@main
struct GameWidgets: WidgetBundle {
@WidgetBundleBuilder
var body: some Widget {
GameStatusWidget()
CharacterDetailWidget()
LeaderboardWidget()
}
}
复制代码
iOS 用户终于没必要再像过去那样进入应用程序内获取天气、新闻资讯、日期等信息,可直接经过在主界面上添加不一样应用、不一样尺寸的组件,关键信息就可直接在主屏幕上一目了然,有点致敬安卓的影子。
好了,今天的讲解就到这里,感兴趣的朋友能够关注个人技术公众号,每周都有优质技术文章推送,微信扫一扫下方二维码便可关注: