共享SwiftUI视图的屏幕截图会导致崩溃

时间:2020-10-10 16:17:52

标签: swift swiftui

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

该视图是来自呈现为一叠纸牌的文本数组的一组问题。我正在尝试获取问题的屏幕截图,并使其与应用程序链接一起共享(测试与愤怒的小鸟的链接)。

我基本上可以使用Asperi对以下问题的回答来捕获屏幕截图: How do I render a SwiftUI View that is not at the root hierarchy as a UIImage?

我的共享表启动,并且我已经能够使用“复制”功能来复制图像,所以我知道它实际上正在获取屏幕截图,但是每当我单击“消息”将其发送给某人时,或者我只是打开共享表,应用程序崩溃了。

该消息表明这是一个内存问题,但没有对此问题进行过多描述。是否有解决此类问题的好方法?我认为在这种情况下,必须与屏幕截图的保存方式有关。

enter image description here

这是我对View和UIView的扩展以呈现图像:

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

这是我的视图的缩写版本-按钮大约在一半位置,应该在底部调用私有函数以从View / UIView扩展中呈现图像,并将“ questionScreenShot”变量设置为呈现的图像,然后将其显示在共享表中。

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 个答案:

答案 0 :(得分:0)

我找到了一个似乎在这里起作用的解决方案。我开始将问题屏幕截图存储为nil的变量开始:

    @State var questionScreenShot: UIImage? = nil

然后我只需要确保在视图出现时将其设置为“ render”,这意味着它将加载UIImage,因此,如果用户单击“共享问题”,它将可以被加载(我认为之前存在问题共享完成后,UIImage不会及时加载的位置。

它还会在消失时将该变量设置为nil。

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