确保在启动共享表以共享图像之前渲染图像?
Posted
技术标签:
【中文标题】确保在启动共享表以共享图像之前渲染图像?【英文标题】:Make sure image is rendered before launching share sheet to share image? 【发布时间】:2020-11-01 21:59:36 【问题描述】:有没有办法确保在我启动尝试共享该图像的工作表之前呈现图像(来自我的应用程序的屏幕截图)?
我有一个我正在启动的共享表,它在显示一堆卡片的视图中获取当前的“卡片”,然后截取存储在变量“questionScreenShot”中的卡片的屏幕截图。这张卡应该与链接一起共享 - 我正在使用来自这个问题的 Asperi 解决方案的变体来生成图像: How do I render a SwiftUI View that is not at the root hierarchy as a UIImage?
当我第一次点击“分享问题”按钮时,卡片没有分享(我只得到链接)。但是,如果我继续运行该应用程序,然后再次单击“共享问题”,我会在此时获得一张图片。
我有一个 if 语句,它应该仅在图像具有值时才启动共享表。在 ShareSheet 启动之前我有断点,这应该是一个不同的方向,因为根据下图中“questionScreenShot”的值,图像似乎仍然为空。
但是,当应用程序实际启动工作表时,它会说我的打印输出中的图像有一些价值:
sharesheet has some value
sharesheet equals Optional(<UIImage:0x282fdb330 anonymous 300, 380>)
这是我的文件,其中包含生成图像的视图扩展名:
import SwiftUI
import UIKit
extension UIView
func asImage() -> UIImage
let renderer = UIGraphicsImageRenderer(bounds: bounds)
return renderer.image rendererContext in
self.layer.render(in: rendererContext.cgContext)
extension View
func asImage() -> UIImage
let controller = UIHostingController(rootView: self)
// locate far out of screen
controller.view.frame = CGRect(x: 0, y: CGFloat(Int.max), width: 1, height: 1)
UIApplication.shared.windows.first!.rootViewController?.view.addSubview(controller.view)
let size = controller.sizeThatFits(in: UIScreen.main.bounds.size)
controller.view.bounds = CGRect(origin: .zero, size: size)
controller.view.sizeToFit()
controller.view.backgroundColor = .clear
let image = controller.view.asImage()
controller.view.removeFromSuperview()
return image
这是我的页面结构,带有共享表按钮,if 语句仅在图像变量具有值时才应该启动共享表:
struct TopicPage: View
//inherit current topic from the PackTopics page, and create a state variable that gets set to a random question.
var currentTopic: Topic
@State private var currentQuestions: [String]
@State private var showShareSheet = false
@State private var rect: CGRect = .zero
let appURL: String = "https://apps.apple.com/us/app/im-curious/id1518506383"
@State var questionScreenShot: UIImage? = nil
@State var shareQuestionVisible: Bool = true
var body: some View
GeometryReader geometry in
Blah Blah Blah
Spacer()
.sheet(isPresented: $showShareSheet, onDismiss:
questionScreenShot = nil
print("Question Screenshot reset to \(questionScreenShot ?? nil)")
)
ShareSheet(activityItems: [questionScreenShot ?? nil, appURL])
//Set the background image.
.navigationBarItems(trailing:
Button(action:
self.questionScreenShot = render()
if self.questionScreenShot != nil
print("sharesheet has some value")
print("sharesheet equals \(questionScreenShot)")
self.showShareSheet = true
else
print("Did not set screenshot")
)
Text("Share Question").bold()
.disabled(!shareQuestionVisible)
)
// Geometry Reader ignores all safe edges
.edgesIgnoringSafeArea(.all)
func removeQuestion(at question: Int)
currentQuestions.remove(at: question)
if currentQuestions.count == 0
self.shareQuestionVisible = false
private func render() -> UIImage
Card(color: currentTopic.color, text: self.currentQuestions[currentQuestions.count-1]).asImage()
编辑:刚刚尝试了 Asperi 将启动共享表调用包装在 DispatchQueue.main.async 中的解决方案,并且行为似乎大致相同:
我尝试更改对 ShareSheet 的调用以匹配 Asperi 的建议,并且行为大致相同。它不会第一次启动屏幕截图,而是第二次启动屏幕截图。
Spacer()
.sheet(isPresented: $showShareSheet, onDismiss:
questionScreenShot = nil
print("Question Screenshot reset to \(questionScreenShot ?? nil)")
)
ShareSheet(activityItems: [questionScreenShot ?? nil, appURL])
//Set the background image.
.navigationBarItems(trailing:
Button(action:
self.questionScreenShot = render()
print("Question Screenshot now set to \(questionScreenShot ?? nil)")
DispatchQueue.main.async
self.showShareSheet = true
)
这是我得到的输出,所以它似乎在第一次和第二次都正确设置了屏幕截图,然后在我关闭共享表时将其重置为零。我确实收到了 CFMessagePort 错误,我不确定这是否与此有关。
Question Screenshot now set to Optional(<UIImage:0x162e24c80 anonymous 300, 380>)
2020-11-02 07:20:02.917212-0600 Travel Conversation Starters[6492:694831] [PPT] Error creating the CFMessagePort needed to communicate with PPT.
Question Screenshot reset to nil
2020-11-02 07:20:12.731769-0600 Travel Conversation Starters[6492:695053] [ShareSheet] connection invalidated
Question Screenshot now set to Optional(<UIImage:0x162e1b970 anonymous 300, 380>)
2020-11-02 07:20:20.276303-0600 Travel Conversation Starters[6492:694831] [PPT] Error creating the CFMessagePort needed to communicate with PPT.
注意:我确实将结构中的变量更改为指向 Images.xcassets 文件夹中的实际图像,而是第一次加载该图像。所以第一次加载太慢似乎有问题。
@State var questionScreenShot: UIImage? = UIImage(named: "Test")
【问题讨论】:
【参考方案1】:这与我对另一个问题的回答有关:Sharing Screenshot of SwiftUI view causes crash
但基本上我只需要确保我向视图添加了一个 OnAppear 代码块,该视图还将 shareQuestion 图像设置为 render()。然后我把它设置回视图的 nil OnDisappear。
【讨论】:
以上是关于确保在启动共享表以共享图像之前渲染图像?的主要内容,如果未能解决你的问题,请参考以下文章
将 SwiftUI 视图渲染到屏幕外并将视图另存为 UIImage 以共享