如何拍摄UIView部分的截图?

时间:2016-09-02 03:20:12

标签: ios swift screenshot wkwebview

我希望用户在Swift中以编程方式按下按钮后继续我的应用程序并获取应用程序的屏幕截图。我知道UIGraphicsGetImageFromCurrentImageContext()需要截图,但我不想要整张屏幕的图片。我希望弹出一个矩形(有点像裁剪工具),用户可以拖动矩形并调整其大小,只截取屏幕的某个部分。我希望矩形超过WKWebView并裁剪网页视图的图片。

2 个答案:

答案 0 :(得分:27)

标准快照技术是drawHierarchy(in:afterScreenUpdates:),将其绘制到图像上下文中。在iOS 10及更高版本中,您可以使用UIGraphicsImageRenderer

extension UIView {

    /// Create image snapshot of view.
    ///
    /// - Parameters:
    ///   - rect: The coordinates (in the view's own coordinate space) to be captured. If omitted, the entire `bounds` will be captured.
    ///   - afterScreenUpdates: A Boolean value that indicates whether the snapshot should be rendered after recent changes have been incorporated. Specify the value false if you want to render a snapshot in the view hierarchy’s current state, which might not include recent changes. Defaults to `true`.
    ///
    /// - Returns: The `UIImage` snapshot.

    func snapshot(of rect: CGRect? = nil, afterScreenUpdates: Bool = true) -> UIImage {
        return UIGraphicsImageRenderer(bounds: rect ?? bounds).image { _ in
            drawHierarchy(in: bounds, afterScreenUpdates: true)
        }
    }
}

你会这样使用它:

let image = webView.snapshot(of: rect)

在iOS 10之前,您将获得图片的一部分,您可以使用CGImage方法cropping(to:)。 E.g:

extension UIView {

    /// Create snapshot
    ///
    /// - Parameters:
    ///   - rect: The coordinates (in the view's own coordinate space) to be captured. If omitted, the entire `bounds` will be captured.
    ///   - afterScreenUpdates: A Boolean value that indicates whether the snapshot should be rendered after recent changes have been incorporated. Specify the value false if you want to render a snapshot in the view hierarchy’s current state, which might not include recent changes. Defaults to `true`.
    ///
    /// - Returns: Returns `UIImage` of the specified portion of the view.

    func snapshot(of rect: CGRect? = nil, afterScreenUpdates: Bool = true) -> UIImage? {
        // snapshot entire view

        UIGraphicsBeginImageContextWithOptions(bounds.size, isOpaque, 0)
        drawHierarchy(in: bounds, afterScreenUpdates: afterScreenUpdates)
        let wholeImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        // if no `rect` provided, return image of whole view

        guard let image = wholeImage, let rect = rect else { return wholeImage }

        // otherwise, grab specified `rect` of image

        guard let cgImage = image.cgImage?.cropping(to: rect * image.scale) else { return nil }
        return UIImage(cgImage: cgImage, scale: image.scale, orientation: .up)
    }

}

使用这个方便的操作员:

extension CGRect {
    static func * (lhs: CGRect, rhs: CGFloat) -> CGRect {
        return CGRect(x: lhs.minX * rhs, y: lhs.minY * rhs, width: lhs.width * rhs, height: lhs.height * rhs)
    }
}

要使用它,你可以这样做:

if let image = webView.snapshot(of: rect) {
    // do something with `image` here
}

对于Swift 2的演绎,请参阅previous revision of this answer

答案 1 :(得分:3)

这是How to capture UIView to UIImage without loss of quality on retina display之前提出的问题,但要在swift(2.3)中进行扩展:

React.createElement(
  "span",
  { className: styles.solution || "solution" },
  data.solution,
  " "
);

因此,您可以使用extension UIView { class func image(view: UIView) -> UIImage? { UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.opaque, 0.0) guard let ctx = UIGraphicsGetCurrentContext() else { return nil } view.layer.renderInContext(ctx) let img = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return img } func image() -> UIImage? { return UIView.image(self) } } 从视图中获取图片,也可以通过询问视图本身UIView.image(theView)

请记住,虽然这很粗糙,可能需要进一步查看线程安全等....