LinkPresentation视图未在SwiftUI中完全加载

时间:2019-09-22 09:14:48

标签: swift swiftui ios13

我正在使用从一篇很棒的文章here中找到的代码,该代码演示了如何在SwiftUI中使用LinkPresentation框架。

但是,我遇到了一个小问题,我找不到解决的办法-链接预览会加载其元数据,但一旦完全加载就不会刷新视图,除非我执行了一些强制刷新视图的操作,例如旋转视图电话。

它们的负载与此相同:

Before Rotating

然后旋转后看起来像这样:

After Rotating

一旦元数据加载,我希望视图完全刷新。我觉得我可能需要在某个地方添加一些绑定,但是我不知道在哪里。任何人都可以帮忙吗?

这是UIViewRepresentable

import SwiftUI
import LinkPresentation

struct URLPreview : UIViewRepresentable {
    var previewURL:URL

    func makeUIView(context: Context) -> LPLinkView {
        LPLinkView(url: previewURL)
    }

    func updateUIView(_ view: LPLinkView, context: Context) {
        // New instance for each update

        let provider = LPMetadataProvider()

        provider.startFetchingMetadata(for: previewURL) { (metadata, error) in
            if let md = metadata {
                DispatchQueue.main.async {
                    view.metadata = md
                    view.sizeToFit()

                }
            }
        }
    }
}

以及它的称呼方式:

struct Content: View {
    var body: some View {
        URLPreview(previewURL: URL(string: "www.apple.com")!)
    }
}

2 个答案:

答案 0 :(得分:1)

LPLinkView 中使用 List 会导致巨大的内存泄漏。最好的办法是使用嵌入在 VStack 中的 ScrollView

ScrollView {
    VStack {
        ForEach(links, id: \.self) { link in
            if let url = URL(string: link) {
                LinkRow(url: url)
            }
        }
    }
    .padding()
}

这将使 LPLinkView 在加载时自行调整大小。

我在一个应用中完成了这项工作,它比使用 List 有了显着的改进。但是有一点需要注意,如果用户在预览仍在加载时很快在屏幕上显示上下滚动的星星,则可能会导致随机崩溃。不幸的是,我还没有找到解决方案。我认为所有这些崩溃的发生都是因为 LPMetadataProvider 要求您在主线程上被调用,显然这在平滑滚动时效果不佳。

答案 1 :(得分:0)

触发重绘是您所需要的。对此不感兴趣,但您可以尝试绑定State CGSize并将帧设置为宽度/高度。

struct URLPreview : UIViewRepresentable {
    var previewURL:URL
    //Add binding
    @Binding var metaSize: CGSize

    func makeUIView(context: Context) -> LPLinkView {
        LPLinkView(url: previewURL)
    }

    func updateUIView(_ view: LPLinkView, context: Context) {
        // New instance for each update

        let provider = LPMetadataProvider()

        provider.startFetchingMetadata(for: previewURL) { (metadata, error) in
            if let md = metadata {
                DispatchQueue.main.async {
                    view.metadata = md
                    view.sizeToFit()
                    //Set binding after resize
                    self.metaSize = view.frame.size
                }
            }
        }
    }
}
struct ContentView: View {
    //can default original state
    @State var metaSize: CGSize = CGSize()

    var body: some View {
        URLPreview(previewURL: URL(string: "www.apple.com")!, metaSize: $metaSize)
            .frame(width: metaSize.width, height: metaSize.height)
    }
}