Sharing Screenshot of SwiftUI view causes crash

最后都变了- 提交于 2021-02-08 07:22:56

问题


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()
    }
}

回答1:


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
            }


来源:https://stackoverflow.com/questions/64295607/sharing-screenshot-of-swiftui-view-causes-crash

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!