首页 > 解决方案 > GeometryReader 和 ZStack 到产品截图

问题描述

我的目标:使用几何阅读器和屏幕截图功能(已经编写)来抓取位于关闭按钮后面的图像的一小部分。

设置:我有一个 ZStack,上面有Image一个较小的按钮(它是本示例的系统映像)。目前,我将关闭按钮与背景图像的顶部对齐,乍一看一切都很好。

但是,当点击关闭按钮时,我需要抓取关闭按钮本身的屏幕截图(匹配框架和大小)。

当我对齐时一切正常,但现在我已经设置ZStack,我的屏幕截图仍然出现在图像的中心。.centeralignment: .top

当点击它时,如何移动GeometryReader包含关闭按钮的屏幕截图以允许屏幕截图成为关闭按钮(以及它背后的一些额外背景)?

我的代码:

struct ImageView: View {
    var body: some View {
        ZStack(alignment: .top) {
            Image("ZoomedBuzz")
                .resizable()
                .aspectRatio(contentMode: .fill)
                .frame(width: UIScreen.main.bounds.width)
                
            GeometryReader { geo in
                Image(systemName: "xmark.circle.fill")
                    .font(.system(size: 80))
                    .border(Color.blue)
                    .onTapGesture {
                        let globalImage = takeScreenshot(origin: geo.frame(in: .global).origin,
                                                         size: geo.size)
                        print(globalImage)
                    }
            }
            .frame(width: 80, height: 80, alignment: .top)
        }
    }
}

截图:

extension UIView {
    var renderedImage: UIImage {
        // rect of capture
        let rect = self.bounds
        // create the context of bitmap
        UIGraphicsBeginImageContextWithOptions(rect.size, false, 0.0)
        let context: CGContext = UIGraphicsGetCurrentContext()!
        self.layer.render(in: context)
        // get a image from current context bitmap
        let capturedImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
        UIGraphicsEndImageContext()
        return capturedImage
    }
}

extension View {
    func takeScreenshot(origin: CGPoint, size: CGSize) -> UIImage {
        let window = UIWindow(frame: CGRect(origin: origin, size: size))
        let hosting = UIHostingController(rootView: self)
        hosting.view.frame = window.frame
        window.addSubview(hosting.view)
        window.makeKeyAndVisible()
        return hosting.view.renderedImage
    }
}

模拟器画面

期望的结果(但在顶部ZStack):

期望的结果

当前结果(在以 为中心的背景图像中间截取屏幕截图ZStack):

当前结果

标签: swiftuigeometryreaderzstack

解决方案


如果您希望 GeometryReader 靠近按钮而不是捕获整个屏幕,您可以将其设置为按钮背景。

不幸的是,我不知道你的截图方法是如何工作的,因此我无法验证它是否适用于你的设置,但现在你可以简单地截图整个 GeometryReader 的框架。

struct ImageView: View {
    
    @State private var geo: GeometryProxy!
    
    var body: some View {
        ZStack(alignment: .top) {
            Image("ZoomedBuzz")
                .resizable()
                .aspectRatio(contentMode: .fill)
                .frame(width: UIScreen.main.bounds.width)
                
            Image(systemName: "xmark.circle.fill")
                .font(.system(size: 80))
                .border(Color.blue)
                .background(rectReader())
                .onTapGesture {
                    let globalImage = takeScreenshot(origin: geo.frame(in: .global).origin,
                                                     size: geo.size)
                    print(globalImage)
                }
        }
    }
    
    private func rectReader() -> some View {
        return GeometryReader { geometry -> AnyView in
            DispatchQueue.main.async {
                self.geo = geometry
            }
            return AnyView(Rectangle().fill(Color.clear))
        }
    }
}

推荐阅读