SwiftUI Widget Extension小組件

iOS 14新推出了Widget Extension插件血筑,基于SwiftUI開發(fā)于购,對于用戶而言叫小組件菱阵,iOS14后廢棄了之前Today Extension崭放,而Widget Extension定制性更高哟楷,支持三種樣式悯仙,小中大2 * 2慷丽、4 * 2卦方、4 * 4(systemSmall嗽仪、systemMedium荒勇、systemLarge)

創(chuàng)建Widget Extension插件

在原有的項目中創(chuàng)建Widget Extension

1、File->New->Target選擇Widget Extension


選擇Widget Extension.png

2闻坚、輸入widget名字下一步

image.png

3沽翔、天氣組件代碼

import WidgetKit
import SwiftUI

struct Provider: TimelineProvider {
    func placeholder(in context: Context) -> SimpleEntry {
        return WeatherPoser.dafaultEntry()
    }
    
    func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -> ()) {
        let entry = WeatherPoser.dafaultEntry()
        completion(entry)
    }
    
    func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
        let currentDate = Date()
        //設定1小時更新一次數(shù)據(jù)
        let updateDate = Calendar.current.date(byAdding: .hour, value: 1, to: currentDate)!
        
        let entry = WeatherPoser.dafaultEntry()
        let timeline = Timeline(entries: [entry], policy: .after(updateDate))
        completion(timeline)
        
        /*
         // 真實網(wǎng)絡請求
         WeatherPoser.requestNow { result in
         if case .success(let now) = result {
         let entry = Entry(date: currentDate, dataList: poster, cityName: String(name), today: now)
         let timeline = Timeline(entries: [entry], policy: .after(updateDate))
         completion(timeline)
         }
         }
         */
        
    }
    
}

struct SimpleEntry: TimelineEntry {
    let date: Date
    let dataList: [WeatherModel]
    let cityName: String
    let today: Now
}

struct WeatherWidgetEntryView : View {
    var entry: Provider.Entry
    @Environment(\.widgetFamily) var family:WidgetFamily
    
    var body: some View {
        switch family {
        case .systemSmall:
            VStack {
                Text("body")
            }
        case .systemMedium:
            MediumWeatherView(entry: entry)
        case .systemLarge:
            VStack {
                Text("body")
            }
        default:
            MediumWeatherView(entry: entry)
        }
    }
}

@main
struct WeatherWidget: Widget {
    let kind: String = "WeatherWidget"
    
    var body: some WidgetConfiguration {
        StaticConfiguration(kind: kind, provider: Provider()) { entry in
            WeatherWidgetEntryView(entry: entry)
        }
        .configurationDisplayName("天氣")
        .description("顯示最近天氣預報")
    }
}

struct WeatherWidget_Previews: PreviewProvider {
    static var previews: some View {
        let entry = WeatherPoser.dafaultEntry()
        WeatherWidgetEntryView(entry: entry)
            .previewContext(WidgetPreviewContext(family: .systemSmall))
    }
}

struct MediumWeatherView: View {
    var entry: Provider.Entry
    var body: some View {
        VStack {
            HStack(alignment: .center){
                Image("blue_loc").frame(width: 12, height: 12, alignment: .center).aspectRatio(contentMode: .fit)
                Text(self.entry.cityName)
                Spacer()
                Text(self.entry.date, style: .date)
            }
            HStack(alignment: .center){
                if let text = self.entry.today.text {
                    Image(text).frame(width: 44, height: 44, alignment: .center).aspectRatio(contentMode: .fit)
                    let temperature = self.entry.today.temperature
                    Text((temperature + "°"))
                        .font(.largeTitle)
                        .fontWeight(.semibold)
                }
                ForEach(entry.dataList) {item in
                    if item.id == 0 {
                        VStack {
                            Text(item.weather)
                            Text(item.temp)
                        }
                    }
                }
                Spacer()
            }
            Spacer()
            HStack(alignment: .center){
                ForEach(entry.dataList) {item in
                    if item.id > 0 {
                        WeatherDayView(item:item)
                    }
                }
            }
        }.padding(11.0)
    }
}

struct WeatherDayView: View {
    var item: WeatherModel
    var body: some View {
        HStack(alignment: .center, spacing: 12){
            Image(self.item.weather).frame(width: 30, height: 30, alignment: .center).aspectRatio(contentMode: .fit)
            VStack(alignment: .leading) {
                Text(self.item.title)
                    .font(.body)
                    .foregroundColor(Color(hue: 0.275, saturation: 0.74, brightness: 0.621))
                Text(self.item.temp)
                    .font(.body)
            }
        }
    }
}


struct Now: Identifiable {
    var temperature: String = ""
    var text: String = ""
    var id: Int = 0
}
struct WeatherModel: Identifiable {
    var weather: String = ""
    var title: String = ""
    var temp: String = ""
    var id: Int = 0
}

struct WeatherPoser {
    static func dafaultEntry() -> SimpleEntry {
        let dataList = [
            WeatherModel(weather: "晴", title: "今天", temp: "20/36°", id: 0),
            WeatherModel(weather: "晴", title: "明天", temp: "20/36°", id: 1),
            WeatherModel(weather: "晴", title: "后天", temp: "20/36°", id: 2),
            WeatherModel(weather: "晴", title: "周四", temp: "20/36°", id: 3)
        ]
        let now = Now(temperature: "30", text: "多云", id: 0)
        return SimpleEntry(date: Date(), dataList: dataList, cityName: "北京市", today: now)
    }
    
}

4、顯示效果


image.png

支持指定尺寸supportedFamilies

StaticConfiguration(kind: kind, provider: Provider()) { entry in
    WeatherWidgetEntryView(entry: entry)
}
.configurationDisplayName("天氣")
.description("顯示最近天氣預報")
.supportedFamilies([.systemMedium])

刷新全部組件

WidgetCenter.shared.reloadAllTimelines()

刷新指定組件

WidgetCenter.shared.reloadTimelines(ofKind: "widgetName")

判斷有沒有配置顯示組件

WidgetCenter.shared.getCurrentConfigurations { result in
      switch result {
      case .success(let widgetInfos):
           if widgetInfos.count > 0 {
              print("組件已配置")
           }
           print(widgetInfos)
       case .failure(let err):
              print(err)
       }
 }

數(shù)據(jù)共享窿凤,需要配置group證書關聯(lián)

let widgetDafault = UserDefaults(suiteName: "group.com.wynter.widget"
widgetDafault?.set("北京市", forKey: "cityName")

let cityName = String(widgetDafault?.string(forKey: "cityName") ?? "北京市")
最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末仅偎,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子雳殊,更是在濱河造成了極大的恐慌橘沥,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,324評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件夯秃,死亡現(xiàn)場離奇詭異座咆,居然都是意外死亡痢艺,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評論 3 392
  • 文/潘曉璐 我一進店門介陶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來堤舒,“玉大人,你說我怎么就攤上這事哺呜∩噻停” “怎么了?”我有些...
    開封第一講書人閱讀 162,328評論 0 353
  • 文/不壞的土叔 我叫張陵弦牡,是天一觀的道長友驮。 經(jīng)常有香客問我,道長驾锰,這世上最難降的妖魔是什么卸留? 我笑而不...
    開封第一講書人閱讀 58,147評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮椭豫,結(jié)果婚禮上耻瑟,老公的妹妹穿的比我還像新娘。我一直安慰自己赏酥,他們只是感情好喳整,可當我...
    茶點故事閱讀 67,160評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著裸扶,像睡著了一般框都。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上呵晨,一...
    開封第一講書人閱讀 51,115評論 1 296
  • 那天魏保,我揣著相機與錄音,去河邊找鬼摸屠。 笑死谓罗,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的季二。 我是一名探鬼主播檩咱,決...
    沈念sama閱讀 40,025評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼胯舷!你這毒婦竟也來了刻蚯?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,867評論 0 274
  • 序言:老撾萬榮一對情侶失蹤桑嘶,失蹤者是張志新(化名)和其女友劉穎炊汹,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體不翩,經(jīng)...
    沈念sama閱讀 45,307評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡兵扬,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,528評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了口蝠。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片器钟。...
    茶點故事閱讀 39,688評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖妙蔗,靈堂內(nèi)的尸體忽然破棺而出傲霸,到底是詐尸還是另有隱情,我是刑警寧澤眉反,帶...
    沈念sama閱讀 35,409評論 5 343
  • 正文 年R本政府宣布昙啄,位于F島的核電站,受9級特大地震影響寸五,放射性物質(zhì)發(fā)生泄漏梳凛。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,001評論 3 325
  • 文/蒙蒙 一梳杏、第九天 我趴在偏房一處隱蔽的房頂上張望韧拒。 院中可真熱鬧,春花似錦十性、人聲如沸叛溢。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,657評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽楷掉。三九已至,卻和暖如春霞势,著一層夾襖步出監(jiān)牢的瞬間烹植,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,811評論 1 268
  • 我被黑心中介騙來泰國打工支示, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留刊橘,地道東北人。 一個月前我還...
    沈念sama閱讀 47,685評論 2 368
  • 正文 我出身青樓颂鸿,卻偏偏與公主長得像促绵,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子嘴纺,可洞房花燭夜當晚...
    茶點故事閱讀 44,573評論 2 353

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