首页 > 解决方案 > 为什么在某些情况下视图的快照看起来可能会大两倍?

问题描述

问题

当使用各种UIView扩展来拍摄 a 的快照时UIView,结果可能看起来比应有的更大(有点放大)。

有关问题的详细信息

我拍摄了 2 的快照UIViews,我们可以在下面调用 viewA 和 viewB。

我已经测试了 3 种不同的代码以获得我正在寻找的结果:一个提供了所需的快照图像,但渲染质量低;另外两个为viewA但为viewB提供了更好质量的图像渲染和正确的结果,尽管快照似乎具有正确的矩形(我检查了矩形),但显示的图像显得太大(好像它们被放大了两次)。

代码

  1. 扩展#1:提供正确的结果,但图像质量低

    extension UIView {
    
        func takeSnapshot() -> UIImage? {
            UIGraphicsBeginImageContext(self.frame.size)
            self.layer.render(in: UIGraphicsGetCurrentContext()!)
            let snapshot = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
    
            return snapshot
        }
    }
    
  2. 扩展#2:提供正确的图像质量,但 viewB 的裁剪图像显示两倍大

    extension UIView {
        func snapshot(of rect: CGRect? = nil, afterScreenUpdates: Bool = true) -> UIImage {
            return UIGraphicsImageRenderer(bounds: rect ?? bounds).image { _ in
                drawHierarchy(in: bounds, afterScreenUpdates: true)
            }
        }
    }
    
  3. 扩展#3:同样,提供正确的图像质量,但 viewB 的裁剪图像显示两倍大

    extension UIView {
        func takeScreenshot() -> UIImage {
            UIGraphicsBeginImageContextWithOptions(self.bounds.size, false, UIScreen.main.scale)
    
            drawHierarchy(in: self.bounds, afterScreenUpdates: true)
            let image = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
    
            if (image != nil) { return image! }
            return UIImage()
        }
    }
    

最后但并非最不重要的一点是,从快照中提取裁剪图像的(简化)代码

    for i in (0...numberOfCroppedImages) {
        let rect    = CGRect(x: CGFloat(i) * snapshot!.size.width / CGFloat(numberOfCroppedImages), y: 0, width: snapshot!.size.width / CGFloat(numberOfCroppedImages), height:snapshot!.size.height)

        // defines the container view for the fragmented snapshots
        let view    = UIView()
        view.frame  = rect


        // defines the layer with the fragment of the snapshot
        let layer           = CALayer()
        layer.frame.size    = rect.size
        let img             = snapshot?.cgImage?.cropping(to: rect)
        layer.contents      = img
        view.layer.addSublayer(layer)
    }

到目前为止尝试的操作

我已经仔细检查了所有内容CGRect,但没有发现任何问题:视图矩形和快照大小似乎是预期的,但是,我一直有太大的渲染图像,扩展名为 #2 和 #3 viewB(viewA 被正确渲染),而扩展#1 提供了正确尺寸的图像,但质量太低而无法充分使用。

这可能是一个问题drawInHierarchy(in: afterScreenUpdates:)吗?或者使用 ? 转换为 cgImage let img = snapshot?.cgImage?.cropping(to: rect)

我会非常感谢任何指点!

标签: iosswiftuiviewsnapshot

解决方案


我发布了一个我发现对我有用的解决方案:

首先,无论视图是否添加到层次结构、裁剪与否,都呈现(就我而言)预期结果(质量和大小方面)的快照扩展:

    extension UIView {

        func takeSnapshot(of rect: CGRect? = nil, afterScreenUpdates: Bool = true) -> UIImage {
            return UIGraphicsImageRenderer(bounds: rect ?? bounds).image { (context) in
                self.layer.render(in: context.cgContext)
            }
        }

    }

然后是在视图中拍摄矩形快照的代码的更新版本:

    let view    = UIView()
    view.frame  = rect
    let img = self.takeSnapshot(of: rect, afterScreenUpdates: true).cgImage
    view.layer.contents = img

这里的区别在于对视图中的矩形进行快照,而不是裁剪整个视图的快照。

我希望这有帮助。


推荐阅读