詳解iOS14 Widget 開發(fā)相關(guān)及易報(bào)錯(cuò)地方處理
首先了解下如何創(chuàng)建
Xcode -> File -> New -> Target 找到 Widget Extension
如果你的 Widget 支持用戶配置屬性,則需要勾選這個(gè)(例如天氣組件,用戶可以選擇城市),不支持的話則不用勾選
了解下創(chuàng)建Widget后,系統(tǒng)給我們生成的文件內(nèi)容
下面這個(gè)代碼是沒有勾選 Include Configuration Intent 的地方
Provider
// Provider,顧名思義為小組件提供信息得一個(gè)struct struct Provider: TimelineProvider { public typealias Entry = SimpleEntry // 編輯屏幕時(shí),左上角選擇添加小組件時(shí)候,第一次展示小組件會(huì)走這個(gè)方法 public func snapshot(with context: Context, completion: @escaping (SimpleEntry) -> ()) { } // 這個(gè)方法內(nèi)可以進(jìn)行網(wǎng)絡(luò)請(qǐng)求,拿到的數(shù)據(jù)保存在對(duì)應(yīng)的 entry 中,調(diào)用 completion 之后會(huì)到刷新小組件 public func timeline(with context: Context, completion: @escaping (Timeline<Entry>) -> ()) { // 例如這是一個(gè)網(wǎng)絡(luò)請(qǐng)求 Network.request { data in let entry = SimpleEntry(date: renderDate, data: data) let timeline = Timeline(entries: [entry], policy: .after(nextRequestDate)) completion(timeline) } } }
Entry
官方解釋: A type that specifies the date to display a widget, and, optionally, indicates the current relevance of the widget's content.
// 我的理解是就是存儲(chǔ)小組件的數(shù)據(jù)的一個(gè)東西 struct SimpleEntry: TimelineEntry { let date: Date let data: Data }
PlacehodlerView
// 這個(gè)是一個(gè)默認(rèn)視圖,例如網(wǎng)絡(luò)請(qǐng)求失敗、發(fā)生未知錯(cuò)誤、第一次展示小組件都會(huì)展示這個(gè)view struct PlaceholderView : View { }
WidgetEntryView
// 這個(gè)是我們需要布局小組件長(zhǎng)什么樣子的view struct StaticWidgetEntryView : View { }
主入口
@main struct StaticWidget: Widget { private let kind: String = "StaticWidget" public var body: some WidgetConfiguration { StaticConfiguration(kind: kind, provider: Provider(), placeholder: PlaceholderView()) { entry in StaticWidgetEntryView(entry: entry) } .configurationDisplayName("My Widget") .description("This is an example widget.") } }
支持多Widget樣式
@main struct MainWidgets: WidgetBundle { @WidgetBundleBuilder var body: some Widget { Widget1() Widget2() } }
勾選 Include Configuration Intent 之后可能出錯(cuò)的地方
如果你的app中設(shè)置了 Class Prefix 這下面這個(gè) ConfigurationIntent.self 則需要加上對(duì)應(yīng)的前綴
例如前綴是 XY 則需要修改為 XYConfigurationIntent.self
@main struct MainWidget: Widget { private let kind: String = "MainWidget" public var body: some WidgetConfiguration { IntentConfiguration(kind: kind, intent: XYConfigurationIntent.self, provider: Provider(), placeholder: PlaceholderView()) { entry in IntentWidgetEntryView(entry: entry) } .configurationDisplayName("My Widget") .description("This is an example widget.") } }
處理Widget點(diǎn)擊事件
Widget 支持三種顯示方式,分別是 systemSmall 、 systemMedium 、 systemLarge
small 樣式只能用 widgetUrl 處理
@ViewBuilder var body: some View { ZStack { AvatarView(entry.character) .widgetURL(url) .foregroundColor(.white) } .background(Color.gameBackground) }
medium 和 large 可以用 Link 或者 widgetUrl 處理,我們看到里面有四個(gè)相同的view,即左邊圖片,右邊文字的,這個(gè)view代碼如下(Link方式)
struct RecipeView: View { let recipe: RecipeModel var body: some View { Link(destination: URL(string: "你的網(wǎng)址")!) { HStack { WebImageView(imageUrl: recipe.squareImageUrl) .frame(width: 65, height: 65) Text(recipe.adjName + recipe.name) .font(.footnote) .bold() .foregroundColor(.black) .lineLimit(3) } } } }
添加 Link 或 widgetUrl 后,點(diǎn)擊每個(gè) RecipeView 都會(huì)觸發(fā)事件,這時(shí)候你需要在主項(xiàng)目中的 AppDelegate 中的如下方法進(jìn)行處理
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool { }
關(guān)于Widget中加載網(wǎng)絡(luò)圖片的時(shí)機(jī)
當(dāng)我們?cè)趂unc timeline(withcompletion)這個(gè)方法中請(qǐng)求到數(shù)據(jù)拿到圖片鏈接后,必須同步把圖片解析出來,否則直接讓對(duì)應(yīng)的WidgetView去load url 是加載不出來的
正確的寫法
Struct Model { ... let image: UIImage } func timeline(with context: Context, completion: @escaping (Timeline<LFPlanEntry>) -> ()) { Network.request { data in // 解析圖片 var image: UIImage? = nil if let imageData = try? Data(contentsOf: url) { image = UIImage(data: imageData) } let model = Model(image: image ?? defalutImage) // 這里給個(gè)默認(rèn)圖片 let entry = SimpleEntry(date: entryDate, data: model) let timeline = Timeline(entries: [entry], policy: .atEnd) completion(timeline) } } Struct WidgetView: View { let model: Model @ViewBuilder var body: some View { Image(uiImage: model.image) .resizable() } }
錯(cuò)誤的寫法(直接丟url給view去加載)
struct WidgetView : View { let model: Model @State private var remoteImage : UIImage? = nil let defaultImage = UIImage(named: "default")! var body: some View { Image(uiImage: self.remoteImage ?? defaultImage) .onAppear(perform: fetchRemoteImage) } func fetchRemoteImage() { guard let url = URL(string: model.url) else { return } URLSession.shared.dataTask(with: url){ (data, response, error) in if let image = UIImage(data: data!){ self.remoteImage = image } else { print(error ?? "") } }.resume() } }
基于我們的app做出來的簡(jiǎn)單效果圖
Widget相關(guān)資料
到此這篇關(guān)于詳解iOS14 Widget 開發(fā)相關(guān)及易報(bào)錯(cuò)地方處理的文章就介紹到這了,更多相關(guān)iOS14 Widget開發(fā)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
iOS開發(fā)中簡(jiǎn)單實(shí)用的幾個(gè)小技巧
大家可能都知道,在開發(fā)過程中我們總會(huì)遇到各種各樣的小問題,有些小問題并不是十分容易解決。在此我就總結(jié)一下,我在開發(fā)中遇到的各種小問題,以及我的解決方法,也算是些小技巧吧,分享給大家,方便大家在iOS開發(fā)的時(shí)候能夠參考借鑒,下面有需要的朋友一起來看看吧。2016-11-11iOS實(shí)現(xiàn)帶動(dòng)畫的環(huán)形進(jìn)度條
這篇文章主要為大家詳細(xì)介紹了iOS實(shí)現(xiàn)帶動(dòng)畫的環(huán)形進(jìn)度條,同時(shí)帶數(shù)字同步效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-01-01移動(dòng)端固定輸入框在底部會(huì)被鍵盤遮擋的解決方法(必看篇)
下面小編就為大家分享關(guān)于移動(dòng)端固定輸入框在底部會(huì)被鍵盤遮擋的解決方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2017-12-12IOS collectionViewCell防止復(fù)用的兩種方法
這篇文章主要介紹了IOS collectionViewCell防止復(fù)用的兩種方法的相關(guān)資料,需要的朋友可以參考下2016-11-11iOS本地推送簡(jiǎn)單實(shí)現(xiàn)代碼
這篇文章主要為大家詳細(xì)介紹了iOS本地推送簡(jiǎn)單實(shí)現(xiàn)代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-09-09