ShareLink 在显示共享表之前运行代码

问题描述 投票:0回答:3

我有一个

ShareLink
来分享图片

ShareLink(item: image) {
    Image(systemName: "square.and.arrow.up")
}

现在在分享这张图片之前,我必须使用一些函数生成它

@State var image: UIImage
var getImage() {
    // some code that updates @State variable
}

我的

ShareLink
本身位于上下文菜单中。我的问题是,每次刷新视图或打开上下文菜单时生成此图像(调用
getImage()
函数)成本太高。如果用户点击此共享链接,然后运行代码,然后将结果显示在共享表中,有什么方法可以运行代码吗?

注意:我知道可以使用 UIKit 作为后备来生成共享表,使用如下函数:

func actionSheet() {
    guard let urlShare = URL(string: "https://developer.apple.com/xcode/swiftui/") else { return }
    let activityVC = UIActivityViewController(activityItems: [urlShare], applicationActivities: nil)
    UIApplication.shared.windows.first?.rootViewController?.present(activityVC, animated: true, completion: nil)
}

如本文所示:https://medium.com/swift-products/sharesheet-uiactivityviewcontroller-swiftui-47abcd69aba6

我想知道是否有办法用新的ios16来做到这一点

ShareLink

我还没有设法让它与 Sharelink 一起使用。这是我正在使用的解决方法:

Button {
    shareCollage()
} label: {
    Label("Share Collage", systemImage: "square.and.arrow.up")
}

调用

func shareCollage() {
    Task {
        if let screenshot = await takeScreenshot() {
            let activityVC = UIActivityViewController(activityItems: [screenshot], applicationActivities: nil)
            
            if UIDevice.current.userInterfaceIdiom == .pad {
                // otherwise iPad crashes
                let thisViewVC = UIHostingController(rootView: self)
                activityVC.popoverPresentationController?.sourceView = thisViewVC.view
            }
            
            UIApplication.shared.connectedScenes.flatMap {($0 as? UIWindowScene)?.windows ?? []}.first {$0.isKeyWindow}?.rootViewController?.present(activityVC, animated: true, completion: nil)
        }
    }
}

来源:https://github.com/charelF/StickerPaste/blob/main/StickerPaste/ContentView.swift

swift swiftui
3个回答
2
投票

这对我有用:

let img = ImageModel(getImage: getImage)
ShareLink(item: img, preview: SharePreview(
    "shareImage",
    image: img
)) {
    Label("shareImage", systemImage: "photo")
}

struct ImageModel: Transferable {
    let getImage: () async -> UIImage?

    static var transferRepresentation: some TransferRepresentation {
        DataRepresentation(exportedContentType: .jpeg) { item in
            try await { () -> Data in
                if let img = await item.getImage(), let jpeg = img.jpegData(compressionQuality: 0.6) {
                    return jpeg
                } else {
                    throw ExportImageError.noImageFound
                }
            }()
        }
    }
}

错误:

enum ExportImageError: Error {
    case noImageFound
}

我在这里遇到的唯一问题是

getImage()
被调用两次,一次用于预览,一次用于导出本身。您可以不使用预览,如下所示:

ShareLink(item: ImageModel(getImage: shareImage), preview: SharePreview(
    "shareImage",
    image: Image("photo")
)) {
    Label("shareImage", systemImage: "text.below.photo.fill")
}

或者以某种方式缓存结果。也许还有更好的方法来做到这一点。


0
投票

我使用

@State var imageForShare: ImageFile? = nil
作为我想分享的图像。

我认为您不需要每次刷新视图时都生成图像。只要图像内容发生变化就生成图像(以

async
方式),这样 SwiftUI 就知道何时需要更新图像。

由于异步生成在后台工作,因此它不会影响您的视图渲染。


0
投票

基于@charelf添加到原始问题的解决方案,我创建了一个

LazyShareLink
来隐藏这种复杂性。理想情况下,苹果将在不久的将来推出类似的东西,它可以完全取代这种自定义实现。

使用方法

LazyShareLink("Share") { ... }

实施

struct LazyShareLink: View {

    let text: LocalizedStringKey
    let prepareData: () -> [Any]?

    init(_ text: LocalizedStringKey, prepareData: @escaping () -> [Any]?) {
        self.text = text
        self.prepareData = prepareData
    }

    var body: some View {
        Button(text, action: openShare)
    }

    private func openShare() {
        guard let data = prepareData() else {
            return
        }
        let activityVC = UIActivityViewController(activityItems: data, applicationActivities: nil)

        if UIDevice.current.userInterfaceIdiom == .pad {
            // otherwise iPad crashes
            let thisViewVC = UIHostingController(rootView: self)
            activityVC.popoverPresentationController?.sourceView = thisViewVC.view
        }

        UIApplication.shared.connectedScenes
            .flatMap { ($0 as? UIWindowScene)?.windows ?? [] }
            .first { $0.isKeyWindow }?
            .rootViewController?
            .present(activityVC, animated: true, completion: nil)
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.