首页 > 解决方案 > 将 UIView 保存为图像会导致其子视图的 zPositioning 失败

问题描述

我需要将我的应用中的视图保存为 .png 图像。该视图包含 4 个子视图,每个子视图通过 zPosition - subview.layer.zPosition 在不同的层上。

主视图 -

我对 UIView 有以下扩展功能。图像保存但忽略了子视图的 zPositioning。Suvbview 在生成的保存图像中以错误的顺序堆叠在一起。我的代码如下:

extension UIView {
    func asImage() -> UIImage {
        if #available(iOS 10.0, *) {
            let renderer = UIGraphicsImageRenderer(bounds: bounds)
            return renderer.image { rendererContext in
                layer.render(in: rendererContext.cgContext)
            }            
        }
    }
}

我这样称呼它:

var snapshot: UIImage? = mainView.asImage()

经过一些谷歌搜索后,我发现手动重新排序子视图然后在每个子视图上调用 rendererContext 可以解决这个问题。它适用于 zPositioning,所有元素现在都正确堆叠,但所有元素现在都失去了相对于 mainView 的 x/y 定位。我可以看到这是因为主视图现在被忽略了,但我正在努力解决这个问题。有人可以帮忙吗?

extension UIView {
    func asImage() -> UIImage {
        if #available(iOS 10.0, *) {
            let renderer = UIGraphicsImageRenderer(bounds: bounds)
            return renderer.image { rendererContext in
                let orderedLayers = self.subviews.sorted(by: {
                    $0.layer.zPosition < $1.layer.zPosition
                })
                for l in orderedLayers {
                    l.layer.render(in: rendererContext.cgContext)
                }
            }            
        }
    }
}

标签: swift

解决方案


我想通了这一点,所以万一其他人遇到这个问题,解决方案是将每个新排序的层添加回父视图(在这种情况下为父视图调用扩展函数时的自身)。修改后的代码如下:

func asImage() -> UIImage {
    if #available(iOS 10.0, *) {
        let renderer = UIGraphicsImageRenderer(bounds: bounds)
        return renderer.image { rendererContext in
            let orderedLayers = self.subviews.sorted(by: {
                $0.layer.zPosition < $1.layer.zPosition
            })
            for l in orderedLayers {
                self.addSubview(l)
            }
            layer.render(in: rendererContext.cgContext)
        } 
    }
} 

推荐阅读