我有一个
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
这对我有用:
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")
}
或者以某种方式缓存结果。也许还有更好的方法来做到这一点。
我使用
@State var imageForShare: ImageFile? = nil
作为我想分享的图像。
我认为您不需要每次刷新视图时都生成图像。只要图像内容发生变化就生成图像(以
async
方式),这样 SwiftUI 就知道何时需要更新图像。
由于异步生成在后台工作,因此它不会影响您的视图渲染。
基于@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)
}
}