iOS14 Widget小组件开发实践5——网络图片的加载

image

SwiftUI中,通过Image来展示图片,例如:

Image("touxiang")

Image(systemName: "arkit")
    .foregroundColor(.orange)
    .font(.system(size: 48))

Image("touxiang")
    .resizable()
    .aspectRatio(contentMode: .fit)

Image(uiImage: UIImage(named: "touxiang"))
        .resizable()
        .frame(width: 50, height: 50)

以上都是使用Image加载本地图片资源,但是SwiftUI中的Image没有提供直接加载URL方式的图片显示,那么如何在SwiftUI中让Image加载网络图片呢,可以采用异步加载网络图片数据,由data转换成UIimage,再给Image展示

struct ContentView : View {
    @State private var remoteImage : UIImage? = nil
    let placeholderOne = UIImage(named: "Picture")
    
    var body: some View {
        Image(uiImage: self.remoteImage ?? placeholderOne!)
            .onAppear(perform: fetchRemoteImage)
    }
    
    func fetchRemoteImage()
    {
        guard let url = URL(string: "http://hdjc8.com/images/logo.png") else { return }
        URLSession.shared.dataTask(with: url){ (data, response, error) in
            if let image = UIImage(data: data!){
                self.remoteImage = image
            }
            else{
                print(error ?? "")
            }
        }.resume()
    }
}

但是这种异步加载图片的方式在Widget中却失效了,Image显示不了图片。
TimelineProvidergetTimelinecompletion(timeline)执行完之后,不再支持图片的异步回调了,所以必须在数据请求回来的处理中采用同步方式,将图片的data获取,转换成UIimage,在赋值给Image展示。

接下里给iOS14 Widget小组件开发实践2——自定义Widget里搭建的古诗视图增加一个网络封面图片显示,效果如下:


根据上面说的,既然异步加载图片不行了,必须在数据请求回来的处理中采用同步方式,将图片的data获取,转换成UIimage。那么我们先来在Poetry里面增加一个UIimage参数:

struct Poetry {
    let content: String // 内容
    let origin: String // 名字
    let author: String // 作者
    var icon: UIImage? = UIImage(named: "touxiang") // 图片
}

因为这个免费的API接口没有返回图片封面数据,所以就自己网上找个图片用来测试。关于图片请求的时机,这里我是将它放在了API接口回调后处理jsonmodel的这一步:

static func poetryFromJson(fromData data: Data) -> Poetry { 
  ......
}
static func modelFromJson(fromData data: Data) -> Poetry {
    let json = try! JSONSerialization.jsonObject(with: data, options: []) as! [String: Any]
    //因为免费接口请求频率问题,如果太频繁了,请求可能失败,这里做下处理,放置crash
    guard let data = json["data"] as? [String: Any] else {
        return Poetry(content: "诗词加载失败,请稍微再试!", origin: "耐依福", author: "佚名")
    }
    let content = data["content"] as! String
    let origin = data["origin"] as! String
    let author = data["author"] as! String
    //这里加入对图片进行同步请求
    var image: UIImage? = nil
    if let iamgeData = try? Data(contentsOf: URL(string: "https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=1058052610,2039041423&fm=26&gp=0.jpg")!) {
        image = UIImage(data: iamgeData)
    }
    return Poetry(content: content, origin: origin, author: author, icon: image)
}

最后在给PoetryWidgetView布局界面:

struct PoetryWidgetView : View {
    let entry: PoetryEntry

    var body: some View {
        HStack(content: {
            Image(uiImage: entry.poetry.icon!)
                .resizable()
                .frame(width: 70, height: 70)
            VStack(alignment: .leading, spacing: 4) {
                Text(entry.poetry.origin)
                    .font(.system(size: 20))
                    .fontWeight(.bold)
                Text(entry.poetry.author)
                    .font(.system(size: 16))
                Text(entry.poetry.content)
                    .font(.system(size: 18))
            }
        })
        .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .leading)
        .padding()
        .background(LinearGradient(gradient: Gradient(colors: [.init(red: 144 / 255.0, green: 252 / 255.0, blue: 231 / 255.0), .init(red: 50 / 204, green: 188 / 255.0, blue: 231 / 255.0)]), startPoint: .topLeading, endPoint: .bottomTrailing))
    }
}

参考资料

https://github.com/fzhlee/SwiftUI-Guide#20Image-Web
SwitUI-实现URL图片显示

你可能感兴趣的:(iOS14 Widget小组件开发实践5——网络图片的加载)