共享 SwiftUI 视图的屏幕截图导致崩溃 [英] Sharing Screenshot of SwiftUI view causes crash

查看:37
本文介绍了共享 SwiftUI 视图的屏幕截图导致崩溃的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在我的 SwiftUI 视图中抓取子视图的屏幕截图,以立即传递到共享表以共享图像.

该视图是来自呈现为一叠卡片的文本数组的一组问题.我正在尝试获取问题的屏幕截图,并将其与应用链接一起共享(使用指向愤怒的小鸟的链接进行测试).

我已经能够基本上使用 Asperi 对以下问题的回答来捕获屏幕截图:

这是我用来渲染图像的 View 和 UIView 扩展:

扩展 UIView {func asImage() ->用户界面{让渲染器 = UIGraphicsImageRenderer(bounds: bounds)返回 renderer.image { rendererContext inlayer.render(在:rendererContext.cgContext)}}}扩展视图{func asImage() ->用户界面{让控制器 = UIHostingController(rootView: self)//定位到屏幕外controller.view.frame = CGRect(x: 0, y: CGFloat(Int.max), width: 1, height: 1)UIApplication.shared.windows.first!.rootViewController?.view.addSubview(controller.view)让 size = controller.sizeThatFits(in: UIScreen.main.bounds.size)controller.view.bounds = CGRect(origin: .zero, size: size)控制器.view.sizeToFit()controller.view.backgroundColor = .clear让图像 = controller.view.asImage()controller.view.removeFromSuperview()返回图像}}

这是我的视图的缩写版本 - 按钮大约在中间位置,应该调用底部的私有函数,该函数从 View/UIView 扩展中呈现图像,并设置questionScreenShot"渲染图像的变量,然后呈现在共享表中.

struct TopicPage:查看{var currentTopic:主题@State 私有变量 currentQuestions: [String]@State private var showShareSheet = false@State var questionScreenShot: UIImage?= 零var主体:一些视图{GeometryReader { 几何输入按钮(动作:{self.questionScreenShot = render()如果 self.questionScreenShot != nil {self.showShareSheet = true} 别的 {打印(没有设置截图")}}) {文本(分享问题").粗体()}.sheet(isPresented: $showShareSheet) {ShareSheet(activityItems: [questionScreenShot!])}}}私有函数渲染()->用户界面{QuestionBox(currentQuestion: self.currentQuestions[0]).asImage()}}

解决方案

我找到了一个似乎在这里有效的解决方案.我开始将 questionScreenShot 存储为 nil 的变量启动:

 @State var questionScreenShot: UIImage?= 零

然后我确保在视图出现时将其设置为渲染",这意味着它会加载 UIImage,因此如果用户点击分享问题"它将准备好加载(我认为之前存在一个问题,即共享完成后 UIImage 没有及时加载).

它还会在消失时将该变量设置回 nil.

.onAppear {self.currentQuestions = currentTopic.questions.shuffled()self.featuredQuestion = currentQuestions.last!self.questionScreenShot = render()}.onDisappear {self.questionScreenShot = nilself.featuredQuestion = nil}

I am grabbing a screenshot of a sub-view in my SwiftUI View to immediately pass to a share sheet in order to share the image.

The view is of a set of questions from a text array rendered as a stack of cards. I am trying to get a screenshot of the question and make it share-able along with a link to the app (testing with a link to angry birds).

I have been able to capture the screenshot using basically Asperi's answer to the below question: How do I render a SwiftUI View that is not at the root hierarchy as a UIImage?

My share sheet launches, and I've been able to use the "Copy" feature to copy the image, so I know it's actually getting a screenshot, but whenever I click "Message" to send it to someone, or if I just leave the share sheet open, the app crashes.

The message says it's a memory issue, but doesn't give much description of the problem. Is there a good way to troubleshoot this sort of thing? I assume it must be something with how the screenshot is being saved in this case.

Here are my extensions of View and UIView to render the image:

extension UIView {
    func asImage() -> UIImage {
        let renderer = UIGraphicsImageRenderer(bounds: bounds)
        return renderer.image { rendererContext in
            
            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
    }
}

Here's an abbreviated version of my view - the button is about halfway down, and should call the private function at the bottom that renders the image from the View/UIView extensions, and sets the "questionScreenShot" variable to the rendered image, which is then presented in the share sheet.

struct TopicPage: View {
    var currentTopic: Topic
    @State private var currentQuestions: [String]
    @State private var showShareSheet = false
    @State var questionScreenShot: UIImage? = nil
    
    var body: some View {
        GeometryReader { geometry in
                Button(action: {
                    self.questionScreenShot = render()
                    if self.questionScreenShot != nil {
                        self.showShareSheet = true
                    } else {
                        print("Did not set screenshot")
                    }

                }) {
                    Text("Share Question").bold()
                }
                .sheet(isPresented: $showShareSheet) {
                    ShareSheet(activityItems: [questionScreenShot!])
                }
        }
    }

    
    private func render() -> UIImage {
        QuestionBox(currentQuestion: self.currentQuestions[0]).asImage()
    }
}

解决方案

I've found a solution that seems to be working here. I start the variable where the questionScreenShot gets stored as nil to start:

    @State var questionScreenShot: UIImage? = nil

Then I just make sure to set it to 'render' when the view appears, which means it loads the UIImage so if the user clicks "Share Question" it will be ready to be loaded (I think there was an issue earlier where the UIImage wasn't getting loaded in time once the sharing was done).

It also sets that variable back to nil on disappear.

.onAppear {
                self.currentQuestions = currentTopic.questions.shuffled()
                self.featuredQuestion = currentQuestions.last!
                self.questionScreenShot = render()
            }
            .onDisappear {
                self.questionScreenShot = nil
                self.featuredQuestion = nil
            }

这篇关于共享 SwiftUI 视图的屏幕截图导致崩溃的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆