2022-04-02--iOS14widget小组件开发
2022-04-02--iOS14widget⼩组件开发
widget 效果展⽰.jpeg
import WidgetKit
import SwiftUI
import Alamofire
import HandyJSON
/// 定义模型
struct Model {
var coin: String
var USD: String
var CNY: String
var Range: String
}
/********************************************
//  定义⽹络请求
********************************************** */
struct ApiRequest {
/// ⽹络请求
/// - Parameters:
///  - coins: 请求的币种数组
///  - completion: 处理的模型数组
static func apiRequest(coins: [[String: String]],completion:  @escaping (Result<[Model], Error>) -> Void) {
var models: [Model] = []
for (_,dic) umerated() {
let url = URL(string: "xxxxxxxxxxxxxx?symbol=\(dic["symbol"]!)")
let url = URL(string: "xxxxxxxxxxxxxx?symbol=\(dic["symbol"]!)")
/// URLSession 设置头⽂件
var request = URLRequest.init(url: url!)
request.addValue("IOS", forHTTPHeaderField: "way")
request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content")
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
guard error == nil else {
/// MARK: -- 即使数据请求失败,也需要创建⼀个默认的模型传递过去,不然会出现列表模糊不清的情况                    models.append(Model(coin: dic["symbol"]!, USD: "-- error", CNY: "--", Range: "--"))
/// MARK:-- 强制返回数据的数量和需要请求的数量⼀致,否则会出现数据丢失的情况
unt == unt {
completion(.success(models))
}
return
}
/// 数据的处理在这⾥要全部完成,需要图⽚下载也应同步处理下载并处理。
var poetry = poetryFromJson(fromData: data!)
in == "加载失败" {
/// 数据解析失败后。展⽰名称,其余展⽰ “ -- ” 即可
}
models.append(poetry)
/// MARK:-- 强制返回数据的数量和需要请求的数量⼀致,否则会出现数据丢失的情况
/// 不能以 idx == unt - 1 的判断来返回数据。必须等到数据全部处理完毕
unt == unt {
金鹰女神2016completion(.success(models))
}
}
}
everybody歌词
}
/
// 解析⽹络请求数据
/// - Parameter data: 请求的数据
/// - Returns: 数据模型
static func poetryFromJson(fromData data: Data) -> Model {
let json = try! JSONSerialization.jsonObject(with: data, options: []) as! [String: Any]
guard let data = json["data"] as? [String: Any] else {
/// 数据解析失败时,返回默认的model
return Model(coin: "加载失败", USD: "--", CNY: "--", Range: "--")
}
/// 测试显⽰和刷新的时间
let currentDate = Date()
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "HH时mm分ss秒"
let dateStr = dateFormatter.string(from: currentDate)
let coin = data["symbol"] as! String
let open = dateStr
let amount = data["amount"] as! String
著名音响品牌
let vol = "-2.2%"
return Model(coin: coin, USD: open, CNY: amount, Range: vol)
}
///  模拟数据
///  只做本地数据展⽰⽤。调试列表样式时可⽤
static func modelForJson() -> [Model] {
var models: [Model] = []
let currentDate = Date()
//设定15秒更新⼀次数据
let updateDate = Calendar.current.date(byAdding: .second, value: 15, to: currentDate)!
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "HH时mm分ss秒"
let dateStr = dateFormatter.string(from: updateDate)
let titles = [["coin":dateStr,"USD":"11111","CNY":"¥1111","Range":"+5.5%"],
["coin":"ETH/USDT","USD":"222222","CNY":"¥22222","Range":"+1.5%"],
["coin":"HT/USDT","USD":"33333","CNY":"¥33333","Range":"-6.1%"],
["coin":"ICP/USDT","USD":"4444","CNY":"¥444444","Range":"+3.50%"],
["coin":"ICP/USDT","USD":"4444","CNY":"¥444444","Range":"+3.50%"],
["coin":"XRP/USDT","USD":"55555","CNY":"¥55555","Range":"-5.56%"]]
for item in titles {
let temp = Model(coin: item["coin"]!, USD: item["USD"]!, CNY: item["CNY"]!, Range: item["Range"]!)
models.append(temp)
}
return models
}
}
靖安王
struct Provider: TimelineProvider {
/
// 预览数据
static  let titles = [["coin":"BTC/USDT","USD":"48059","CNY":"¥248202","Range":"+5.5%"],
["coin":"ETH/USDT","USD":"3399.52","CNY":"¥33885","Range":"+1.5%"],
["coin":"ETC/USDT","USD":"9.2991","CNY":"¥48822","Range":"-6.1%"],
["coin":"ICP/USDT","USD":"22.19","CNY":"¥120052","Range":"+3.50%"],
["coin":"XRP/USDT","USD":"0.008527","CNY":"¥8522","Range":"-5.56%"],
["coin":"ADA/USDT","USD":"0.008527","CNY":"¥8522","Range":"-5.56%"]]
/// 占位视图
func placeholder(in context: Context) -> SimpleEntry {
var models: [Model] = []
for item in Provider.titles {
let temp = Model(coin: item["coin"]!, USD: item["USD"]!, CNY: item["CNY"]!, Range: item["Range"]!)
models.append(temp)
}
return SimpleEntry(date: Date(), models: models)
}
/// 快照
func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -> ()) {
var models: [Model] = []
for item in Provider.titles {
let temp = Model(coin: item["coin"]!, USD: item["USD"]!, CNY: item["CNY"]!, Range: item["Range"]!)
models.append(temp)
}
let entry = SimpleEntry(date: Date(), models: models)
completion(entry)
}
/// 数据更新
func getTimeline(in context: Context, completion: @escaping (Timeline<SimpleEntry>) -> ()) {
//  设定5分钟更新⼀次数据,设置5秒更新也不起作⽤,系统决定更新时间,⼤概在5分钟左右
let currentDate = Date()
let updateDate = Calendar.current.date(byAdding: .minute, value: 5, to: currentDate)
let titles = [["symbol":"BTC/USDT"],
["symbol":"ZRX/USDT"],
["symbol":"VET/USDT"],
["symbol":"XMR/USDT"],
["symbol":"XLM/USDT"],
["symbol":"XLM/USDT"]]
ApiRequest.apiRequest(coins: titles) { result in
var models: [Model]
if case .success(let response) = result {
models = response
} else {
models = [Model(coin: "--", USD: "--", CNY: "--", Range: "--")]
}
给自己一句鼓励的话
let entry = SimpleEntry(date: currentDate, models: models)
/// MARK:-- 此处需要特别注意⚠
/// MARK:-- 在数据全部处理完毕之后进⾏传递。
/// MARK:--  .after(updateDate!) 在设定的 5分钟后更新数据,实际更新时间是由系统控制的。⼤概在 5-6 分钟之间            let timeline = Timeline(entries: [entry], policy: .after(updateDate!))
completion(timeline)
}
}
}
struct SimpleEntry: TimelineEntry {
let date: Date
/// 相当于模型数组
let models: [Model]
let models: [Model]
}
/// ⾃定义View
struct StarexWidgetListView: View {
/// MARK:-- 貌似直接设置Model 取值时会有错误。
var coin: String
var USD: String
var CNY: String
var Range: String
var RangeColor: Color
var body: some View {
let height: CGFloat = 30
/// MARK: -- 添加点击事件。
/// 尝试在 StarexWidgetEntryView 的 ForEach 中添加时会导致布局错乱        Link(destination: URL(string: "url://Coin---\(coin)")!) {
HStack(alignment: .center, spacing: 0) {
Text(coin)
.font(.system(size: 15))吴忠旅游景点大全
.multilineTextAlignment(.leading)
.frame(height: height, alignment: .center)
.foregroundColor(Color.black)
.padding(10)
Spacer()
VStack(alignment: .trailing, spacing: 2) {
Text(USD)
.font(.system(size: 15))
.multilineTextAlignment(.trailing)
.frame(height: height/2, alignment: .top)
.foregroundColor(Color.black)
Text(CNY)
.font(.system(size: 12))
.multilineTextAlignment(.trailing)
.frame(height: height/2, alignment: .top)
.
ay)
}.frame(maxHeight: height)
Text(Range)
.font(.system(size: 14))
.multilineTextAlignment(.center)
.frame(width: 70,height: height, alignment: .center)
.foregroundColor(Color.white)
.background(RangeColor)
.cornerRadius(4)
.padding(EdgeInsets(top: 0, leading: 10, bottom: 0, trailing: 10))            }
.frame(maxHeight: height,alignment: .center)
.
environment(\.colorScheme, .dark)
}
}
}
// View
struct StarexWidgetEntryView : View {
var entry: Provider.Entry
@State private var selected = 0
var body: some View {
GeometryReader { geometry in
VStack {
HStack(alignment: .center, spacing: 4) {
Image("icon")
.resizable()
.frame(width: 28, height: 28)
.scaledToFill()
.ignoresSafeArea(.all)
Text("xxxx⾏情")
.ay)
.frame(width: 100,height: 40)
.multilineTextAlignment(.leading)
.font(.system(size: 15))

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。