iOS中Widget的構(gòu)建

什么是widget

iOS Widget是一種可以放置在 iOS 設(shè)備主屏幕上的小型應(yīng)用程序,提供了一個快速訪問和瀏覽信息的方式。 Widget可以顯示各種類型的內(nèi)容,例如天氣、日歷、媒體播放器、時鐘等等。

iOS Widget 的最大特點是可以在主屏幕上快速查看并與應(yīng)用程序進(jìn)行交互,而無需打開應(yīng)用程序。 Widget 需要使用 WidgetKit 框架來創(chuàng)建和管理,WidgetKit提供了各種各樣的組件和 API,使得開發(fā)者可以在 Widget中實現(xiàn)豐富的功能和交互體驗。

本文要實現(xiàn)的Demo效果如下圖所示,顯示的是當(dāng)前時間的Widget。

新建widget

首先直接新建一個target,因為widget實際上就是一個target,所顯示的數(shù)據(jù)是依賴宿主App的,創(chuàng)建完widgetxcode會幫我們新建好示例代碼。

示例代碼中有幾個類了解才能知道如何正確構(gòu)建widget。

TimelineEntry

這個類是用來給widget提供數(shù)據(jù)的,我們可以簡單理解為提供數(shù)據(jù)的demo,唯一的要求是必須要有一個表示時間的屬性var date: Date { get },這個屬性的作用我們稍后解釋,定義一個TimelineEntry結(jié)構(gòu)體如下:

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變量用來顯示當(dāng)前時間的小時和分鐘。

TimelineProvider

這是一個協(xié)議,還是看一段官方的解釋:

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.

這個協(xié)議告訴WidgetKit什么時候更新widget,就是給WidgetKit提供數(shù)據(jù)源,數(shù)據(jù)源就是上面的TimelineEntry實體,當(dāng)然還包括更新策略也就是在什么時間需要更新,協(xié)議里面有幾個方法需要實現(xiàn):

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

這個方法是提供一個站位視圖,因為我們?yōu)?code>WidgetKit提供的數(shù)據(jù)有可能是異步請求的,這時如果添加widget時,數(shù)據(jù)可能還沒準(zhǔn)備好,此時我們可以提供一個站位視圖,讓用戶知道大概得widget樣子,這里簡單的用當(dāng)前時間初始化了SimpleEntry。

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

這個方法是提供靜態(tài)快照,當(dāng)我們添加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)
    }

這個方法是提供一組數(shù)據(jù)用于顯示,這里我們提供了基于當(dāng)前時間的60組數(shù)據(jù),每個entry數(shù)據(jù)的date間隔一分鐘,并放入了一個entries數(shù)組里面,并告知了刷新策略是.atEnd,也就是在60組數(shù)據(jù)顯示完后再更新,此時又會基于當(dāng)前時間提供60組數(shù)據(jù),每個entry數(shù)據(jù)的date值間隔一分鐘,循環(huán)如此。

可以發(fā)現(xiàn)getSnapshotgetTimeline都利用逃逸閉包來提供entry,這表明方法里面可以進(jìn)行異步的操作,例如可以進(jìn)行網(wǎng)絡(luò)請求,在網(wǎng)絡(luò)請求成功后構(gòu)建entry在利用閉包返回,而placeholder則沒有提供逃逸閉包,所以這里盡量提供簡單的數(shù)據(jù)。

構(gòu)建view

利用上面的幾個類組合起來構(gòu)建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是唯一標(biāo)識符,WidgetKitkind來管理widget,StaticConfiguration是一個配置類,這里需要傳入kindprovider,在閉包中需要返回entryView,configurationDisplayNamedescription是當(dāng)我們添加時widget顯示的名字和描述信息。

總結(jié)

本文簡單的介紹了iOSwidget的構(gòu)建,當(dāng)然widget和宿主之間是可以進(jìn)行通信的,比如共享數(shù)據(jù)同時widget也可以和用戶完成交互后,利用用戶的交互信息在更新狀態(tài),widget的使用主要需要明白entery的構(gòu)建和其中通過provider如何進(jìn)行流轉(zhuǎn)的。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容