123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151 |
- //
- // UIScrollView+SwCapture.swift
- // SwViewCapture
- //
- // Created by chenxing.cx on 16/2/26.
- // Copyright © 2016年 Startry. All rights reserved.
- //
- import Foundation
- import WebKit
- public extension UIScrollView {
-
- func swContentCapture (_ completionHandler: @escaping (_ capturedImage: UIImage?) -> Void) {
-
- self.isCapturing = true
-
- // Put a fake Cover of View
- let snapShotView = self.snapshotView(afterScreenUpdates: false)
- snapShotView?.frame = CGRect(x: self.frame.origin.x, y: self.frame.origin.y, width: (snapShotView?.frame.size.width)!, height: (snapShotView?.frame.size.height)!)
- self.superview?.addSubview(snapShotView ?? UIView())
-
- // Backup all properties of scrollview if needed
- let bakFrame = self.frame
- let bakOffset = self.contentOffset
- let bakSuperView = self.superview
- let bakIndex = self.superview?.subviews.firstIndex(of: self)
-
- // Scroll To Bottom show all cached view
- if self.frame.size.height < self.contentSize.height {
- self.contentOffset = CGPoint(x: 0, y: self.contentSize.height - self.frame.size.height)
- }
-
- self.swRenderImageView({ [weak self] (capturedImage) -> Void in
- // Recover View
-
- let strongSelf = self!
-
- strongSelf.removeFromSuperview()
- strongSelf.frame = bakFrame
- strongSelf.contentOffset = bakOffset
- bakSuperView?.insertSubview(strongSelf, at: bakIndex!)
-
- snapShotView?.removeFromSuperview()
-
- strongSelf.isCapturing = false
-
- completionHandler(capturedImage)
- })
-
- }
-
- fileprivate func swRenderImageView(_ completionHandler: @escaping (_ capturedImage: UIImage?) -> Void) {
- // Rebuild scrollView superView and their hold relationship
- let swTempRenderView = UIView(frame: CGRect(x: 0, y: 0, width: self.contentSize.width, height: self.contentSize.height))
- self.removeFromSuperview()
- swTempRenderView.addSubview(self)
-
- self.contentOffset = CGPoint.zero
- self.frame = swTempRenderView.bounds
-
- // Swizzling setFrame
- let method: Method = class_getInstanceMethod(object_getClass(self), #selector(setter: UIView.frame))!
- let swizzledMethod: Method = class_getInstanceMethod(object_getClass(self), #selector(UIView.swSetFrame(_:)))!
- method_exchangeImplementations(method, swizzledMethod)
-
- // Sometimes ScrollView will Capture nothing without defer;
- DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + Double(Int64(0.3 * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)) { () -> Void in
- let bounds = self.bounds
- UIGraphicsBeginImageContextWithOptions(bounds.size, false, UIScreen.main.scale)
-
- if (self.swContainsWKWebView()) {
- self.drawHierarchy(in: bounds, afterScreenUpdates: true)
- }else{
- self.layer.render(in: UIGraphicsGetCurrentContext()!)
- }
- let capturedImage = UIGraphicsGetImageFromCurrentImageContext()
- UIGraphicsEndImageContext()
-
- method_exchangeImplementations(swizzledMethod, method)
-
- completionHandler(capturedImage)
- }
- }
-
-
- // Simulate People Action, all the `fixed` element will be repeate
- // SwContentCapture will capture all content without simulate people action, more perfect.
- func swContentScrollCapture (_ completionHandler: @escaping (_ capturedImage: UIImage?) -> Void) {
-
- self.isCapturing = true
-
- // Put a fake Cover of View
- let snapShotView = self.snapshotView(afterScreenUpdates: true)
- snapShotView?.frame = CGRect(x: self.frame.origin.x, y: self.frame.origin.y, width: (snapShotView?.frame.size.width)!, height: (snapShotView?.frame.size.height)!)
- self.superview?.addSubview(snapShotView!)
-
- // Backup
- let bakOffset = self.contentOffset
-
- // Divide
- let page = floorf(Float(self.contentSize.height / self.bounds.height))
-
- UIGraphicsBeginImageContextWithOptions(self.contentSize, false, UIScreen.main.scale)
-
- self.swContentScrollPageDraw(0, maxIndex: Int(page), drawCallback: { [weak self] () -> Void in
- let strongSelf = self
-
- let capturedImage = UIGraphicsGetImageFromCurrentImageContext()
- UIGraphicsEndImageContext()
-
- // Recover
- strongSelf?.setContentOffset(bakOffset, animated: false)
- snapShotView?.removeFromSuperview()
-
- strongSelf?.isCapturing = false
-
- completionHandler(capturedImage)
- })
-
- }
-
- fileprivate func swContentScrollPageDraw (_ index: Int, maxIndex: Int, drawCallback: @escaping () -> Void) {
-
- self.setContentOffset(CGPoint(x: 0, y: CGFloat(index) * self.frame.size.height), animated: false)
- let splitFrame = CGRect(x: 0, y: CGFloat(index) * self.frame.size.height, width: bounds.size.width, height: bounds.size.height)
-
- DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + Double(Int64(0.3 * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)) { () -> Void in
- self.drawHierarchy(in: splitFrame, afterScreenUpdates: true)
-
- if index < maxIndex {
- self.swContentScrollPageDraw(index + 1, maxIndex: maxIndex, drawCallback: drawCallback)
- }else{
- drawCallback()
- }
- }
- }
- }
- public extension UIWebView {
-
- func swContentCapture (_ completionHandler: @escaping (_ capturedImage: UIImage?) -> Void) {
- self.scrollView.swContentCapture(completionHandler)
- }
-
- func swContentScrollCapture (_ completionHandler: @escaping (_ capturedImage: UIImage?) -> Void) {
- self.scrollView.swContentScrollCapture(completionHandler)
- }
-
- }
|