如何在SwiftUI中的小部件中使用LinkPresentation框架来显示URL图像预览?
下面是WidgetExtension的示例代码,它应该显示使用LinkPresentation检索到的链接预览图像。我猜这些小部件不会直接加载url数据,但需要使用geTimeline以某种方式获取并在那里定义?怎么做的 在Xcode中使用标准小部件模板只是添加元数据如何在SwiftUI中的小部件中使用LinkPresentation框架来显示URL图像预览?,swift,swiftui,Swift,Swiftui,下面是WidgetExtension的示例代码,它应该显示使用LinkPresentation检索到的链接预览图像。我猜这些小部件不会直接加载url数据,但需要使用geTimeline以某种方式获取并在那里定义?怎么做的 在Xcode中使用标准小部件模板只是添加元数据 import WidgetKit import SwiftUI import LinkPresentation struct SimpleEntry: TimelineEntry { let date: Date }
import WidgetKit
import SwiftUI
import LinkPresentation
struct SimpleEntry: TimelineEntry {
let date: Date
}
struct LinkPresentationWidgetEntryView : View {
var entry: Provider.Entry
var body: some View {
//Text(entry.date, style: .time)
VStack{
MetadataView(vm: LinkViewModel(link: "https://www.wsj.com/articles/global-stock-markets-dow-update-03-03-2021-11614761029?mod=markets_lead_pos1"))
}
}
}
class LinkViewModel : ObservableObject {
let metadataProvider = LPMetadataProvider()
@Published var metadata: LPLinkMetadata?
@Published var image: UIImage?
init(link : String) {
guard let url = URL(string: link) else {
return
}
metadataProvider.startFetchingMetadata(for: url) { (metadata, error) in
guard error == nil else {
assertionFailure("Error")
return
}
DispatchQueue.main.async {
self.metadata = metadata
}
guard let imageProvider = metadata?.imageProvider else { return }
imageProvider.loadObject(ofClass: UIImage.self) { (image, error) in
guard error == nil else {
// handle error
return
}
if let image = image as? UIImage {
// do something with image
DispatchQueue.main.async {
self.image = image
}
} else {
print("no image available")
}
}
}
}
}
struct MetadataView : View {
@StateObject var vm : LinkViewModel
var body: some View {
VStack {
if let uiImage = vm.image {
Image(uiImage: uiImage)
.resizable()
//.scaledToFill()
//.clipped()
.frame(width: 60, height: 60)
}
}
}
}
AFAIK WidgetKit不观察
视图
s,只渲染一次,然后丢弃。因此,使用@StateObject
的方法不起作用,因为当请求返回时,WidgetKit已经放弃了视图
正如您已经猜到的,您必须在getSnapshot
或getTimeline
中执行每个异步任务
下面是一个重用部分代码的最小工作示例。当然,您可能希望根据需要调整url的配置、错误处理和时间线策略
请注意,我不知道这是否被视为最佳实践……我只知道它有效:)
导入WidgetKit
导入快捷键
进口意向
导入链接演示文稿
结构提供程序:IntentTimelineProvider{
func占位符(在上下文中:context)->SimpleEntry{
SimpleEntry(日期:date(),配置:ConfigurationContent(),图像:UIImage(系统名:“wifi.slash”))
}
func getSnapshot(对于配置:configurationcontent,在上下文:context中,完成:@escaping(SimpleEntry)->()){
获取图像(用于:https://www.wsj.com/articles/global-stock-markets-dow-update-03-03-2021-11614761029?mod=markets_lead_pos1,调用:{image in
let entry=SimpleEntry(日期:date(),配置:配置,映像:映像)
完成(进入)
})
}
func getTimeline(对于配置:configurationcontent,在上下文:context中,完成:@escaping(Timeline)->()){
getSnapshot(对于:配置,在:上下文中,完成:{entry in
let timeline=timeline(条目:[entry],策略:。在(Date().advanced(by:3600))之后)
完成(时间表)
})
}
}
结构SimpleEntry:TimelineEntry{
日期:日期
let配置:配置内容
让图像:UIImage?
}
结构WidgetEntryView:视图{
var条目:Provider.entry
var body:一些观点{
如果let image=entry.image{
Image(uiImage:Image).resizeable().scaledToFill()
}否则{
文本(“无法加载图像…”)
}
}
}
func fetchImage(对于url:String,调用回调:@escaping(UIImage)->Void={uin}){
让metadataProvider=LPMetadataProvider()
guard let url=url(字符串:url)else{
返回
}
metadataProvider.startFetchingMetadata(for:url){(元数据,错误)位于
保护错误==nil else{
断言失败(“错误”)
返回
}
guard let imageProvider=元数据?.imageProvider else{return}
装入对象(类:UIImage.self){(图像,错误)在
保护错误==nil else{
//处理错误
返回
}
如果让图像=图像为UIImage{
//用图像做点什么
DispatchQueue.main.async{
回调(图像)
}
}否则{
打印(“无可用图像”)
}
}
}
}
@主要
struct MyWidget:Widget{
让种类:String=“Widget”
变量主体:一些WidgetConfiguration{
IntentConfiguration(种类:种类,意图:ConfigurationContent.self,提供程序:提供程序()){中的条目
WidgetEntryView(条目:条目)
}
.configurationDisplayName(“我的小部件”)
.description(“这是一个示例小部件”)
}
}
这很有效!如果您的模型是一个多维模型,比如JSON数组,它有一个URL列表,您希望从中获取图像,那么您知道如何修改这个模型吗?struct Model:TimelineEntry{var date:date var widgetData:[JSONModel]}我不太确定我是否理解正确……您想获取一个常量URL,该URL用JSON响应,其中包含指向某些图像的n个URL列表,并想在小部件上显示这n个图像吗?在这种情况下,您仍然必须在getSnapshot
或getTimeline
中完成所有工作。首先使用类似于fetchJSON(url,onComplete:{imageURLs in…})的内容获取json。在回调中,您必须使用
fetchImage`并计算已经触发了多少次回调。一旦您的计数器到达imageURLs.count,您就完成了,可以调用getSnapshot
的completion
回调。是的,这就是我正在尝试做的。我在getTimeline中获取了包含JSON中URL的数据,对于这些URL,我需要图像。我已将var images:[UIImage]添加到我的模型/时间线条目中,在将数据发布到时间线完成中之前,我正在尝试更新每个url的模型以获取图像。您能帮我查看我的代码并修复它吗?您可以通过twitter(at)a3igner的一些代码与我取得联系,这些代码应该适合您的需求,但您必须自己调整它以适应您的业务逻辑。