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 用戶終於沒必要再像過去那樣進入應用程序內獲取天氣、新聞資訊、日期等信息,可直接經過在主界面上添加不一樣應用、不一樣尺寸的組件,關鍵信息就可直接在主屏幕上一目瞭然,有點致敬安卓的影子。
好了,今天的講解就到這裏,感興趣的朋友能夠關注個人技術公衆號,每週都有優質技術文章推送,微信掃一掃下方二維碼便可關注: