WidgetKit框架詳細(xì)解析(二) —— 一個(gè)基于WidgetKit和SwiftUI的簡(jiǎn)單示例(一)

版本記錄

版本號(hào) 時(shí)間
V1.0 2020.11.20 星期五

前言

WidgetKit是iOS14的新的SDK蝙茶,接下來(lái)幾篇我們就一起看一下這個(gè)專題歌馍。感興趣的可以看下面幾篇文章肢簿。
1. WidgetKit框架詳細(xì)解析(一) —— 基本概覽(一)

開始

首先看下主要內(nèi)容:

在本教程中僧凤,您將向一個(gè)大型SwiftUI應(yīng)用添加小部件(widget)豆巨,重用其視圖以顯示該應(yīng)用存儲(chǔ)庫(kù)中的條目剩辟。內(nèi)容來(lái)自翻譯

下面就看下寫作環(huán)境

Swift 5, iOS 14, Xcode 12

接著就是正文了

在今年的WWDC Platforms State of the Union中看到新的主屏幕小部件(widgets)后往扔,我就知道必須為自己喜歡的應(yīng)用制作一個(gè)贩猎!在主屏幕上看到它真是太好了。我并不孤單萍膛。每個(gè)人都在做吭服!蘋果公司知道自己是贏家,并提供了一個(gè)由三部分組成的代碼蝗罗,以使所有人開始使用艇棕。

已經(jīng)發(fā)布了幾本指導(dǎo)手冊(cè),那么本教程有什么不同串塑?好吧欠肾,我決定將一個(gè)小部件添加到由一組開發(fā)人員編寫的相當(dāng)大的SwiftUI應(yīng)用程序中,但沒(méi)人是我拟赊。有大量的代碼可供篩選,以查找構(gòu)建窗口小部件所需的內(nèi)容粹淋。而且所有這些都沒(méi)有考慮到小部件的編寫吸祟。因此,請(qǐng)跟隨我桃移,向我展示如何做到屋匕。

注意:您將需要Xcode 12 beta。您還需要運(yùn)行iOS 14的iOS設(shè)備借杰。Catalina可以过吻。如果您有運(yùn)行Big Sur BetaMac [partition],則可以嘗試在其中運(yùn)行代碼,以防它無(wú)法在Catalina上運(yùn)行纤虽。

最重要的是乳绕,目前這是一個(gè)真正的bleeding-edge APIWWDC演示中出現(xiàn)的內(nèi)容不是Xcode 12 beta 1的一部分逼纸。您可能會(huì)遇到一些不穩(wěn)定的情況洋措。就是說(shuō),Widgets很酷杰刽,很有趣菠发!

在打開啟動(dòng)程序項(xiàng)目之前,請(qǐng)打開Terminal贺嫂,cdstarter / emitron-iOS-development文件夾滓鸠,然后運(yùn)行以下命令:

scripts/generate_secrets.sh

您正在生成運(yùn)行項(xiàng)目所需的一些機(jī)密文件。

現(xiàn)在第喳,在starter / emitron-iOS-development文件夾中打開Emitron項(xiàng)目糜俗。這需要一些時(shí)間才能獲取一些軟件包,因此墩弯,這里有一些有關(guān)項(xiàng)目的信息吩跋,您可以在等待的同時(shí)進(jìn)行。

Emitronraywenderlich.com應(yīng)用程序渔工。如果您是訂閱者(subscriber)锌钮,則一定已將其安裝在iPhoneiPad上。它可以讓您流式傳輸視頻引矩,并且梁丘,如果您具有專業(yè)訂閱,則可以下載視頻以進(jìn)行離線播放旺韭。

該項(xiàng)目是開源的氛谜。您可以在其GitHub存儲(chǔ)庫(kù)GitHub repository,中閱讀有關(guān)它的信息,當(dāng)然区端,歡迎您為它的改進(jìn)做出貢獻(xiàn)值漫。

您下載的starter版進(jìn)行了一些修改:

  • 設(shè)置是最新的,iOS Deployment Target14.0织盼。
  • Downloads / DownloadService.swift中杨何,注釋了兩個(gè)在Xcode beta 1中引起錯(cuò)誤的promise語(yǔ)句。下載服務(wù)是針對(duì)專業(yè)訂閱的沥邻,本教程不需要它危虱。
  • Guardpost / Guardpost.swift中,將authSession唐全?.prefersEphemeralWebBrowserSession設(shè)置為false埃跷,從而避免每次構(gòu)建和運(yùn)行應(yīng)用程序時(shí)都需要輸入登錄詳細(xì)信息。您仍然必須點(diǎn)擊Sign in,提示您使用raywenderlich.com登錄弥雹。點(diǎn)擊Continue垃帅。首次構(gòu)建和運(yùn)行時(shí),您可能仍必須輸入電子郵件和密碼缅糟,但是在隨后的構(gòu)建和運(yùn)行中挺智,點(diǎn)擊Continue會(huì)跳過(guò)登錄表單。

到目前為止窗宦,Xcode已經(jīng)安裝了所有軟件包赦颇。在模擬器中構(gòu)建并運(yùn)行。

忽略有關(guān)HashableSwiftyJSON的警告赴涵。 滾動(dòng)和播放在Xcode beta 1中效果不佳媒怯,但是您不會(huì)在本教程中對(duì)此進(jìn)行修復(fù)。 如果滾動(dòng)“太多”髓窜,則該應(yīng)用程序?qū)⒈罎ⅰ?也不是你的問(wèn)題扇苞。


WidgetKit

本教程全部關(guān)于向Emitron添加閃亮的新小部件。


Adding a Widget Extension

首先添加帶有File ? New ? Target…widget extension寄纵。

Create a new target

搜索widget鳖敷,選擇Widget Extension并點(diǎn)擊Next

將其命名為EmitronWidget,并確保未選中Include Configuration Intent

Don’t select Include Configuration Intent

有兩種窗口小部件配置(widget configurations)StaticIntent程拭。 具有IntentConfiguration的小部件使用Siri Intents來(lái)使用戶自定義小部件參數(shù)定踱。

單擊Finish并同意激活方案(activate-scheme)對(duì)話框:

1. Running Your Widget

小部件模板(widget template)提供了許多您只需自定義的樣板代碼。它可以直接使用恃鞋,因此崖媚,您可以立即設(shè)置所有內(nèi)容,以確保在準(zhǔn)備測(cè)試代碼時(shí)一切都能順利運(yùn)行恤浪。

注意:Xcode 12 beta 1模擬器不會(huì)在widget gallery中顯示您的widget畅哑。因此,在將來(lái)的某個(gè)Beta版本之前水由,您必須在iOS 14設(shè)備上構(gòu)建并運(yùn)行荠呐。如果您沒(méi)有可用的設(shè)備,則可以運(yùn)行Widget scheme而不是主Emitron scheme砂客,該Widget將出現(xiàn)在模擬器的主屏幕上直秆。

在項(xiàng)目導(dǎo)航器中,選擇頂級(jí)Emitron文件夾對(duì)targets進(jìn)行簽名鞭盟。更改bundle identifier,并為每個(gè)target的每個(gè)版本設(shè)置team瑰剃。

注意:對(duì)于widget齿诉,您可能會(huì)遇到一個(gè)明顯的Xcode bug,該bug將三個(gè)版本中的兩個(gè)的簽名標(biāo)識(shí)設(shè)置為Distribution。如果看到此錯(cuò)誤粤剧,請(qǐng)打開Build Settings歇竟,搜索distribution并將簽名標(biāo)識(shí)更改為Apple Development

最后一個(gè)陷阱:確保小部件的bundle ID前綴與應(yīng)用程序的ID匹配抵恋。這意味著您將需要在“ ios”“ EmitronWidget”之間插入dev以獲取your.prefix.emitron.ios.dev.EmitronWidget焕议。

OK,現(xiàn)在連接您的iOS設(shè)備弧关,選擇Emitron scheme和您的設(shè)備盅安,然后構(gòu)建并運(yùn)行。登錄世囊,然后關(guān)閉應(yīng)用程序别瞭,然后在主窗口的空白區(qū)域上按,直到圖標(biāo)開始抖動(dòng)株憾。

點(diǎn)擊右上角的+按鈕蝙寨,然后向下滾動(dòng)以找到raywenderlich

Scroll down in widget gallery

選擇它可以查看三種尺寸的快照:

Snapshots of the three widget sizes

點(diǎn)擊Add Widget以在屏幕上查看您的小部件:

Your widget on the home screen

點(diǎn)擊widget以重新打開Emitron

您的小部件widget起作用了嗤瞎! 現(xiàn)在墙歪,您只需要使其顯示來(lái)自Emitron的信息即可。


Defining Your Widget

使您的小部件顯示應(yīng)用程序?yàn)槊總€(gè)教程顯示的一些信息是很有意義的贝奇。

Card view in the Emitron app

此視圖在UI / Shared / Content List / CardView.swift中定義虹菲。 我的第一個(gè)想法是將窗口widget target添加到此文件中。 但這需要添加越來(lái)越多的文件弃秆,以容納Emitron中所有復(fù)雜的連接届惋。

您真正需要的只是Text視圖。 這些圖片很可愛(ài)菠赚,但是您需要包括持久性基礎(chǔ)結(jié)構(gòu)以防止它們消失脑豹。

您將復(fù)制相關(guān)Text視圖的布局。 它們使用幾個(gè)實(shí)用程序擴(kuò)展衡查,因此找到這些文件并將EmitronWidgetExtension target添加到其中:

Add the widget target to these files

注意:確保注意到圖像頂部Assets瘩欺。

CardView顯示ContentListDisplayable對(duì)象的屬性。 這是Displayable / ContentDisplayable.swift中定義的協(xié)議:

protocol ContentListDisplayable: Ownable {
  var id: Int { get }
  var name: String { get }
  var cardViewSubtitle: String { get }
  var descriptionPlainText: String { get }
  var releasedAt: Date { get }
  var duration: Int { get }
  var releasedAtDateTimeString: String { get }
  var parentName: String? { get }
  var contentType: ContentType { get }
  var cardArtworkUrl: URL? { get }
  var ordinal: Int? { get }
  var technologyTripleString: String { get }
  var contentSummaryMetadataString: String { get }
  var contributorString: String { get }
  // Probably only populated for screencasts
  var videoIdentifier: Int? { get }
}

您的widget僅需要name拌牲,cardViewSubtitle俱饿,descriptionPlainTextreleasedAtDateTimeString。 因此塌忽,您將為這些屬性創(chuàng)建一個(gè)結(jié)構(gòu)拍埠。

1. Creating a TimelineEntry

創(chuàng)建一個(gè)新的名為WidgetContent.swiftSwift文件,并確保其targetsemitronEmitronWidgetExtension

Create WidgetContent with targets emitron and widget

它應(yīng)該在EmitronWidget組中土居。

現(xiàn)在枣购,將此代碼添加到新文件中:

import WidgetKit

struct WidgetContent: TimelineEntry {
  var date = Date()
  let name: String
  let cardViewSubtitle: String
  let descriptionPlainText: String
  let releasedAtDateTimeString: String
}

要在窗口小部件中使用WidgetContent嬉探,它必須符合TimelineEntry。 唯一必需的屬性是date棉圈,您可以將其初始化為當(dāng)前日期涩堤。

2. Creating an Entry View

接下來(lái),創(chuàng)建一個(gè)視圖以顯示四個(gè)String屬性分瘾。 創(chuàng)建一個(gè)新的SwiftUI View文件胎围,并將其命名為EntryView.swift。 確保其target僅是EmitronWidgetExtension德召,并且也應(yīng)位于EmitronWidget組中:

Create EntryView with only the widget as target

現(xiàn)在白魂,用以下代碼替換struct EntryView的內(nèi)容:

let model: WidgetContent

var body: some View {
  VStack(alignment: .leading) {
    Text(model.name)
      .font(.uiTitle4)
      .lineLimit(2)
      .fixedSize(horizontal: false, vertical: true)
      .padding([.trailing], 15)
      .foregroundColor(.titleText)
    
    Text(model.cardViewSubtitle)
      .font(.uiCaption)
      .lineLimit(nil)
      .foregroundColor(.contentText)
    
    Text(model.descriptionPlainText)
      .font(.uiCaption)
      .fixedSize(horizontal: false, vertical: true)
      .lineLimit(2)
      .lineSpacing(3)
      .foregroundColor(.contentText)
    
    Text(model.releasedAtDateTimeString)
      .font(.uiCaption)
      .lineLimit(1)
      .foregroundColor(.contentText)
  }
  .background(Color.cardBackground)
  .padding()
  .cornerRadius(6)
}

您實(shí)質(zhì)上是從CardView復(fù)制Text視圖并添加填充間距。

完全刪除EntryView_Previews氏捞。

3. Creating Your Widget

現(xiàn)在開始定義窗口widget碧聪。 打開EmitronWidget.swift并在該行中雙擊SimpleEntry

public typealias Entry = SimpleEntry

選擇Editor ? Edit All in Scope,并將名稱更改為WidgetContent液茎。 這將導(dǎo)致一些錯(cuò)誤逞姿,您將在接下來(lái)的幾個(gè)步驟中進(jìn)行修復(fù)。 首先刪除聲明:

struct WidgetContent: TimelineEntry {
  public let date: Date
}

現(xiàn)在捆等,此聲明是多余的滞造,并且與WidgetContent.swift中的聲明沖突。

4. Creating a Snapshot Entry

provider的一種方法提供了一個(gè)快照條目栋烤,以顯示在widget gallery中谒养。 為此,您將使用特定的WidgetContent對(duì)象明郭。

import語(yǔ)句的下面买窟,添加此全局對(duì)象:

let snapshotEntry = WidgetContent(
  name: "iOS Concurrency with GCD and Operations",
  cardViewSubtitle: "iOS & Swift",
  descriptionPlainText: """
    Learn how to add concurrency to your apps! \
    Keep your app's UI responsive to give your \
    users a great user experience.
    """,
  releasedAtDateTimeString: "Jun 23 2020 ? Video Course (3 hrs, 21 mins)")

這是我們的并發(fā)視頻課程的更新,該課程在WWDC第2天發(fā)布薯定。

現(xiàn)在始绍,將snapshot(with:completion:)的第一行替換為:

let entry = snapshotEntry

當(dāng)您在gallery中查看此小部件時(shí),它將顯示此條目话侄。

5. Creating a Temporary Timeline

小部件需要一個(gè)TimelineProvider才能為其提供TimelineEntry類型的條目亏推。 它會(huì)在條目的date屬性指定的時(shí)間顯示每個(gè)條目。

最重要的provider方法是timeline(with:completion:)年堆。 它已經(jīng)有一些代碼來(lái)構(gòu)造時(shí)間軸吞杭,但是您沒(méi)有足夠的條目。 因此变丧,注釋掉最后兩行以外的所有內(nèi)容芽狗,并添加以下行:

let entries = [snapshotEntry]

您正在創(chuàng)建一個(gè)僅包含snapshotEntryentries數(shù)組。

6. Creating a Placeholder View

小部件在等待實(shí)際時(shí)間軸條目時(shí)顯示其PlaceholderView痒蓬。 您還將為此使用snapshotEntry童擎。

以此替換Text視圖:

EntryView(model: snapshotEntry)

WWDC代碼中還顯示了一個(gè)特殊的修飾符曼月,該修飾符使視圖的內(nèi)容模糊不清,以表明這是一個(gè)占位符柔昼,而不是真實(shí)的東西。 是這樣的:

.isPlaceholder(true)

WWDC視頻中看起來(lái)很酷炎辨,但是在Xcode 12 beta 1中沒(méi)有編譯捕透。有關(guān)更多信息,請(qǐng)參閱Apple開發(fā)者論壇中的此項(xiàng) this entry碴萧。

7. Defining Your Widget

最后乙嘀,您可以將所有這些部分放在一起。

首先破喻,刪除EmitronWidgetEntryView虎谢。 您將改用EntryView

現(xiàn)在曹质,將EmitronWidget的內(nèi)部替換為以下內(nèi)容:

private let kind: String = "EmitronWidget"

public var body: some WidgetConfiguration {
  StaticConfiguration(
    kind: kind, 
    provider: Provider(), 
    placeholder: PlaceholderView()
  ) { entry in
    EntryView(model: entry)
  }
  .configurationDisplayName("RW Tutorials")
  .description("See the latest video tutorials.")
}

這三個(gè)字符串是您想要的:kind描述您的窗口小部件婴噩,最后兩個(gè)字符串顯示在庫(kù)中每個(gè)窗口小部件上方的尺寸。

在您的設(shè)備上構(gòu)建并運(yùn)行羽德,登錄几莽,然后關(guān)閉該應(yīng)用以查看您的小部件。

如果仍然顯示時(shí)間宅静,請(qǐng)將其刪除并重新添加章蚣。

Widget gallery with snapshot entry

這是中等大小的小部件現(xiàn)在的樣子:

The medium size widget on the home screen

只有中等大小的小部件看起來(lái)不錯(cuò),因此請(qǐng)修改您的小部件以僅提供該大小姨夹。 在.description下面添加此修飾符:

.supportedFamilies([.systemMedium])

接下來(lái)纤垂,您將直接從應(yīng)用程序的存儲(chǔ)庫(kù)中為時(shí)間線提供真實(shí)的條目!


Providing Timeline Entries

該應(yīng)用程序?qū)⒃?code>Data / ContentRepositories / ContentRepository.swift中創(chuàng)建的contents中顯示ContentListDisplayable對(duì)象的數(shù)組磷账。 要與您的小部件widget共享此信息峭沦,您將創(chuàng)建一個(gè)應(yīng)用程序組。 然后够颠,在ContentRepository.swift中熙侍,將文件寫入此應(yīng)用程序組,并在EmitronWidget.swift中讀取該文件履磨。

1. Creating an App Group

在項(xiàng)目頁(yè)面上蛉抓,選擇emitron target。 在Signing & Capabilities選項(xiàng)卡中剃诅,單擊+ Capability巷送,然后將App Group拖到窗口中。 將其命名為group.your.prefix.emitron.contents矛辕;確保適當(dāng)替換your.prefix笑跛。

現(xiàn)在付魔,選擇EmitronWidgetExtension target并添加App Group功能。 滾動(dòng)瀏覽App Group以查找并選擇group.your.prefix.emitron.contents飞蹂。

2. Writing the Contents File

ContentRepository.swift的頂部几苍,在import Combine語(yǔ)句的下面,添加以下代碼:

import Foundation

extension FileManager {
  static func sharedContainerURL() -> URL {
    return FileManager.default.containerURL(
      forSecurityApplicationGroupIdentifier: "group.your.prefix.emitron.contents"
    )!
  }
}

這只是獲取應(yīng)用程序組容器的URL的一些標(biāo)準(zhǔn)代碼陈哑。 確保替換您的應(yīng)用標(biāo)識(shí)符前綴妻坝。

現(xiàn)在,在var contents下面惊窖,添加此輔助方法:

  func writeContents() {
    let widgetContents = contents.map {
      WidgetContent(name: $0.name, cardViewSubtitle: $0.cardViewSubtitle,
      descriptionPlainText: $0.descriptionPlainText, 
      releasedAtDateTimeString: $0.releasedAtDateTimeString)
    }
    let archiveURL = FileManager.sharedContainerURL()
      .appendingPathComponent("contents.json")
    print(">>> \(archiveURL)")
    let encoder = JSONEncoder()
    if let dataToSave = try? encoder.encode(widgetContents) {
      do {
        try dataToSave.write(to: archiveURL)
      } catch {
        print("Error: Can't write contents")
        return
      }
    }
  }

在這里刽宪,您將創(chuàng)建一個(gè)WidgetContent對(duì)象的數(shù)組,每個(gè)對(duì)象用于存儲(chǔ)庫(kù)中的每個(gè)項(xiàng)目界酒。 您將它們分別轉(zhuǎn)換為JSON并將其保存到app group的容器中圣拄。

let archiveURL行設(shè)置一個(gè)斷點(diǎn)。

設(shè)置contents后毁欣,您將調(diào)用此方法庇谆。 將此didSet閉包添加到contents中:

didSet {
  writeContents()
}

如果Xcode在警告WidgetContent。 跳轉(zhuǎn)到WidgetContent的定義署辉,使其符合Codable

struct WidgetContent: Codable, TimelineEntry {

現(xiàn)在族铆,在模擬器中構(gòu)建并運(yùn)行該應(yīng)用程序。 在斷點(diǎn)處哭尝,widgetContents具有20個(gè)值哥攘。

繼續(xù)執(zhí)行程序并在應(yīng)用程序中向下滾動(dòng)。 在斷點(diǎn)處材鹦,widgetContents現(xiàn)在具有40個(gè)值逝淹。 因此,您可以控制與小部件共享多少項(xiàng)桶唐。

停止應(yīng)用程序栅葡,禁用斷點(diǎn),然后從調(diào)試控制臺(tái)復(fù)制URL文件夾路徑并在Finder中定位尤泽。 看一下contents.json欣簇。

接下來(lái),轉(zhuǎn)到并設(shè)置widget以讀取此文件坯约。

3. Reading the Contents File

EmitronWidget.swift中熊咽,添加相同的FileManager代碼:

extension FileManager {
  static func sharedContainerURL() -> URL {
    return FileManager.default.containerURL(
      forSecurityApplicationGroupIdentifier: "group.your.prefix.emitron.contents"
    )!
  }
}

確保更新您的前綴。

將此幫助程序方法添加到Provider

func readContents() -> [Entry] {
  var contents: [WidgetContent] = []
  let archiveURL = 
    FileManager.sharedContainerURL()
      .appendingPathComponent("contents.json")
  print(">>> \(archiveURL)")

  let decoder = JSONDecoder()
  if let codeData = try? Data(contentsOf: archiveURL) {
    do {
      contents = try decoder.decode([WidgetContent].self, from: codeData)
    } catch {
      print("Error: Can't decode contents")
    }
  }
  return contents
}

這將讀取您保存到應(yīng)用程序組容器中的文件闹丐。

取消注釋timeline(with:completion:)中的代碼横殴,然后替換此行:

var entries: [WidgetContent] = []

使用下面

var entries = readContents()

接下來(lái),修改注釋和for循環(huán)以將日期添加到條目中:

// Generate a timeline by setting entry dates interval seconds apart,
// starting from the current date.
let currentDate = Date()
let interval = 5
for index in 0 ..< entries.count {
  entries[index].date = Calendar.current.date(byAdding: .second,
    value: index * interval, to: currentDate)!
}

刪除for循環(huán)下面的let entry行卿拴。

之后的那一行設(shè)置時(shí)間軸運(yùn)行并指定刷新策略衫仑。 在這種情況下梨与,時(shí)間軸將在用完所有當(dāng)前條目后刷新。

在您的設(shè)備上構(gòu)建并運(yùn)行文狱,登錄并加載列表粥鞋。 然后關(guān)閉該應(yīng)用程序,添加您的小部件并觀看它每5秒更新一次瞄崇。

Widget updating entry every 5 seconds

我可以整天看這個(gè)陷虎。

如果您沒(méi)有滾動(dòng)列表,則該widget將在20個(gè)項(xiàng)目后用完所有條目杠袱。如果等待那么長(zhǎng)時(shí)間,您會(huì)在刷新時(shí)看到它暫停窝稿。

注意:這是Beta版軟件楣富。如果未獲得預(yù)期的結(jié)果,請(qǐng)嘗試從設(shè)備中刪除該應(yīng)用伴榔,然后重新啟動(dòng)設(shè)備纹蝴。另外,請(qǐng)記住踪少,小部件并不是要以秒為單位測(cè)量時(shí)間間隔塘安。在教程設(shè)置中,非常短的間隔只是更加方便援奢。但是結(jié)果是兼犯,時(shí)間軸刷新的等待時(shí)間感覺(jué)很長(zhǎng)!最后一條警告:不要讓5秒小部件在設(shè)備上運(yùn)行集漾,因?yàn)樗鼤?huì)耗盡電池電量切黔。


Enabling User Customization

我為時(shí)間軸間隔選擇了5秒,因此無(wú)需等待很長(zhǎng)時(shí)間即可看到更新具篇。如果您想要更短或更長(zhǎng)的間隔纬霞,只需更改代碼中的值即可∏裕或者...創(chuàng)建一個(gè)intent诗芜,讓您可以通過(guò)在主屏幕上直接編輯小部件來(lái)設(shè)置時(shí)間間隔化撕!

注意:使用intent更改時(shí)間間隔時(shí)末患,直到widget刷新其時(shí)間軸,您才會(huì)看到效果玛瘸。

1. Adding an Intent

首先熔恢,添加您的intent:創(chuàng)建一個(gè)新文件(Command-N)脐湾,搜索intent,選擇SiriKit Intent Definition File并將其命名為TimelineInterval叙淌。確保其target同時(shí)是emitronEmitronWidgetExtension秤掌。

intent側(cè)邊欄的左下角愁铺,單擊+,然后選擇New Intent闻鉴。

Add new intent

intent命名為TimelineInterval茵乱。 如圖所示,使用Category View設(shè)置Custom Intent

Custom intent with category view

并添加一個(gè)名為Integer類型的interval的參數(shù)孟岛,其默認(rèn)值瓶竭,最小值和最大值(如所示)和Type Field。 或設(shè)置您自己的值和/或使用步進(jìn)器渠羞。

Add interval parameter

2. Reconfiguring Your Widget

EmitronWidget.swift中斤贰,將小部件重新配置為IntentConfiguration

Provider協(xié)議更改為IntentTimelineProvider次询。

struct Provider: IntentTimelineProvider {

snapshot(with:completion:)定義為:

public func snapshot(
  for configuration: TimelineIntervalIntent, 
  with context: Context, 
  completion: @escaping (Entry) -> Void
) {

現(xiàn)在荧恍,將timeline(with:completion:)的定義更改為:

public func timeline(
  for configuration: TimelineIntervalIntent, 
  with context: Context, 
  completion: @escaping (Timeline<Entry>) -> Void
) {

timeline(for:with:completion)中,更改interval以使用配置參數(shù):

let interval = configuration.interval as! Int

最后屯吊,在EmitronWidget中送巡,將StaticConfiguration(kind:provider:placeholder :)更改為此:

IntentConfiguration(
  kind: kind, 
  intent: TimelineIntervalIntent.self, 
  provider: Provider(), 
  placeholder: PlaceholderView()
) { entry in

在您的設(shè)備上構(gòu)建并運(yùn)行,登錄并加載列表盒卸。 關(guān)閉應(yīng)用程序骗爆,添加小部件,然后長(zhǎng)按該小部件蔽介。 它會(huì)翻轉(zhuǎn)以顯示Edit Widget按鈕摘投。

Edit widget button

點(diǎn)擊此按鈕更改間隔值

Change the interval value
Setting a new interval

本教程向您展示了如何利用大型應(yīng)用程序中的代碼來(lái)創(chuàng)建一個(gè)小部件,以顯示該應(yīng)用程序自己的存儲(chǔ)庫(kù)中的項(xiàng)目虹蓄。 以下是一些您可以添加到Emitron小部件中的想法:

  • 為大型窗口小部件設(shè)計(jì)一個(gè)視圖谷朝,該視圖顯示兩個(gè)或更多條目。 查看AppleEmojiRangers示例應(yīng)用程序武花,以了解如何為小部件系列修改EntryView圆凰。
  • 將一個(gè)widgetURL添加到EntryView,以便點(diǎn)按該小部件可在該項(xiàng)目的詳細(xì)信息視圖中打開Emitron体箕。
  • 添加intent以使用戶可以從小部件設(shè)置應(yīng)用程序的過(guò)濾器专钉。

后記

本篇主要講述了基于WidgetKitSwiftUI的簡(jiǎn)單示例,感興趣的給個(gè)贊或者關(guān)注~~~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末累铅,一起剝皮案震驚了整個(gè)濱河市跃须,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌娃兽,老刑警劉巖菇民,帶你破解...
    沈念sama閱讀 216,692評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡第练,警方通過(guò)查閱死者的電腦和手機(jī)阔馋,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,482評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)娇掏,“玉大人呕寝,你說(shuō)我怎么就攤上這事∮の啵” “怎么了下梢?”我有些...
    開封第一講書人閱讀 162,995評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)塞蹭。 經(jīng)常有香客問(wèn)我孽江,道長(zhǎng),這世上最難降的妖魔是什么番电? 我笑而不...
    開封第一講書人閱讀 58,223評(píng)論 1 292
  • 正文 為了忘掉前任竟坛,我火速辦了婚禮,結(jié)果婚禮上钧舌,老公的妹妹穿的比我還像新娘。我一直安慰自己涎跨,他們只是感情好洼冻,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,245評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著隅很,像睡著了一般撞牢。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上叔营,一...
    開封第一講書人閱讀 51,208評(píng)論 1 299
  • 那天屋彪,我揣著相機(jī)與錄音,去河邊找鬼绒尊。 笑死畜挥,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的婴谱。 我是一名探鬼主播蟹但,決...
    沈念sama閱讀 40,091評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼谭羔!你這毒婦竟也來(lái)了华糖?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,929評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤瘟裸,失蹤者是張志新(化名)和其女友劉穎客叉,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,346評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡兼搏,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,570評(píng)論 2 333
  • 正文 我和宋清朗相戀三年卵慰,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片向族。...
    茶點(diǎn)故事閱讀 39,739評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡呵燕,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出件相,到底是詐尸還是另有隱情再扭,我是刑警寧澤,帶...
    沈念sama閱讀 35,437評(píng)論 5 344
  • 正文 年R本政府宣布夜矗,位于F島的核電站泛范,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏紊撕。R本人自食惡果不足惜罢荡,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,037評(píng)論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望对扶。 院中可真熱鬧区赵,春花似錦、人聲如沸浪南。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,677評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)络凿。三九已至骡送,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間絮记,已是汗流浹背摔踱。 一陣腳步聲響...
    開封第一講書人閱讀 32,833評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留怨愤,地道東北人派敷。 一個(gè)月前我還...
    沈念sama閱讀 47,760評(píng)論 2 369
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像撰洗,于是被迫代替她去往敵國(guó)和親膀息。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,647評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容