// // UIView+Extension.swift // taiji // // Created by 泰极科技 on 2019/5/15. // Copyright © 2019 泰极科技. All rights reserved. // import UIKit public extension UIView { func screenSnapScreen() -> UIImage? { //截取整个屏幕 guard let window = UIApplication.shared.keyWindow else { return nil } // 用下面这行而不是UIGraphicsBeginImageContext(),因为前者支持Retina UIGraphicsBeginImageContextWithOptions(window.bounds.size, false, 0.0) window.layer.render(in: UIGraphicsGetCurrentContext()!) let image = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return UIImage.init(data: image?.jpegData(compressionQuality: 0.5) ?? Data()) //image } func asImage() -> UIImage? { if #available(iOS 10.0, *) { let renderer = UIGraphicsImageRenderer(bounds: bounds) return renderer.image { rendererContext in layer.render(in: rendererContext.cgContext) } } else { UIGraphicsBeginImageContextWithOptions(frame.size, true, UIScreen.main.scale) layer.render(in: UIGraphicsGetCurrentContext()!) let image = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return image // Fallback on earlier versions } } /// 截屏Image var captureImage: UIImage? { // 参数①:截屏区域 参数②:是否透明 参数③:清晰度 UIGraphicsBeginImageContextWithOptions(frame.size, true, UIScreen.main.scale) layer.render(in: UIGraphicsGetCurrentContext()!) let image = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return image } func setCorners(corners: UIRectCorner, radio: CGFloat) { let maskPath = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radio, height: radio)) let maskLayer = CAShapeLayer() maskLayer.frame = self.bounds maskLayer.path = maskPath.cgPath self.layer.mask = maskLayer } func setRadio(radio: CGFloat) { self.layer.cornerRadius = radio // self.layer.mask = maskLayer } func drawFertileView(type: Int) { backgroundColor = UIColor.rgbColorFromHex(0xD8E9FA) var corners: UIRectCorner = [] if type == 1 { corners = [.topLeft, .bottomLeft] } else if type == 3 { corners = [.topRight, .bottomRight] } else if type == 4 { corners = .allCorners } let maskPath = UIBezierPath(roundedRect: CGRect(x: 0, y: bounds.height/2-11, width: bounds.width, height: 22), byRoundingCorners: corners, cornerRadii: CGSize(width: 11, height: 11)) let maskLayer = CAShapeLayer() maskLayer.frame = self.bounds maskLayer.path = maskPath.cgPath self.layer.mask = maskLayer } func drawMenstrualView(type: Int) { // left = 1, middle, right, full, none backgroundColor = UIColor.rgbColorFromHex(0xFFDFEA) let bezierPath = UIBezierPath() let circlePath = UIBezierPath(ovalIn: CGRect(x: bounds.width/2-16, y: bounds.height/2-16, width: 32, height: 32)) var squarePath = UIBezierPath() if type == 1 { squarePath = UIBezierPath(roundedRect: CGRect(x: bounds.width/2, y: bounds.height/2-6.5, width: bounds.width, height: 13), cornerRadius: 0) } else if type == 3 { squarePath = UIBezierPath(roundedRect: CGRect(x: 0, y: bounds.height/2-6.5, width: bounds.width/2, height: 13), cornerRadius: 0) } else if type == 2 { squarePath = UIBezierPath(roundedRect: CGRect(x: 0, y: bounds.height/2-6.5, width: bounds.width, height: 13), cornerRadius: 0) } else { squarePath = UIBezierPath(roundedRect: CGRect(x: bounds.width/2-1, y: bounds.height/2-1, width: 2, height: 2), cornerRadius: 0) } squarePath.append(circlePath) bezierPath.append(squarePath) let maskLayer = CAShapeLayer() maskLayer.frame = self.bounds maskLayer.path = bezierPath.cgPath self.layer.mask = maskLayer } func setDefault() { self.layer.shadowColor = UIColor.rgbaColorFromHex(0x3D5A80, alpha: 0.1).cgColor self.layer.shadowOffset = CGSize.zero self.layer.shadowRadius = 6 self.layer.shadowOpacity = 1 self.layer.cornerRadius = 6 } // MARK: 添加渐变色图层 func gradientColor(_ text: String, _ font: UIFont, offsetY: CGFloat = 0, textAlignment: NSTextAlignment = NSTextAlignment.center) { // layoutIfNeeded() var b: CGRect! if offsetY == 0 { b = self.bounds } else { b = CGRect(x: 0, y: offsetY, width: self.bounds.size.width, height: self.bounds.size.height) } let label = UILabel() label.text = text label.font = font label.textAlignment = textAlignment label.frame = b let gradient = CAGradientLayer() gradient.colors = [UIColor(red: 0.23, green: 0.98, blue: 0.99, alpha: 1).cgColor, UIColor(red: 0.21, green: 0.71, blue: 1, alpha: 1).cgColor] gradient.startPoint = CGPoint(x: 0, y: 0) gradient.endPoint = CGPoint(x: 1.1155598958333333, y: 1) gradient.frame = b self.layer.insertSublayer(gradient, at: 0) self.mask = label // self.layer.masksToBounds = false // guard startPoint.x >= 0, startPoint.x <= 1, startPoint.y >= 0, startPoint.y <= 1, endPoint.x >= 0, endPoint.x <= 1, endPoint.y >= 0, endPoint.y <= 1 else { // return // } // // 外界如果改变了self的大小,需要先刷新 // layoutIfNeeded() // // var gradientLayer: CAGradientLayer! // removeGradientLayer() // // gradientLayer = CAGradientLayer() // gradientLayer.frame = self.layer.bounds // gradientLayer.startPoint = startPoint // gradientLayer.endPoint = endPoint // gradientLayer.colors = colors // gradientLayer.cornerRadius = self.layer.cornerRadius // gradientLayer.masksToBounds = true // // 渐变图层插入到最底层,避免在uibutton上遮盖文字图片 // self.layer.insertSublayer(gradientLayer, at: 0) // self.backgroundColor = UIColor.clear // // self如果是UILabel,masksToBounds设为true会导致文字消失 // self.layer.masksToBounds = false } func gradientColor1(_ text: String, _ font: UIFont, cornerRadius: CGFloat = 4) { layoutIfNeeded() let button = UIButton() button.setTitle(text, for: .normal) button.frame = self.bounds button.layer.cornerRadius = cornerRadius button.layer.borderWidth = 1 button.layer.masksToBounds = true button.titleLabel?.font = font button.titleLabel?.textAlignment = .center let gradient = CAGradientLayer() gradient.colors = [UIColor(red: 0.23, green: 0.98, blue: 0.99, alpha: 1).cgColor, UIColor(red: 0.21, green: 0.71, blue: 1, alpha: 1).cgColor] gradient.startPoint = CGPoint(x: 0, y: 0) gradient.endPoint = CGPoint(x: 1.1155598958333333, y: 1) gradient.frame = self.bounds self.layer.insertSublayer(gradient, at: 0) self.mask = button } // MARK: 移除渐变图层 // (当希望只使用backgroundColor的颜色时,需要先移除之前加过的渐变图层) func removeGradientLayer() { self.mask = nil if let sl = self.layer.sublayers { for layer in sl { if layer.isKind(of: CAGradientLayer.self) { layer.removeFromSuperlayer() } } } } func removeShapeLayer() { self.mask = nil if let sl = self.layer.sublayers { for layer in sl { if layer.isKind(of: CAShapeLayer.self) { layer.removeFromSuperlayer() } } } } } extension UIScrollView { /// 截长屏Image var captureLongImage: UIImage? { var image: UIImage? = nil UIGraphicsBeginImageContext(contentSize) let formerContentOffset = contentOffset let formerFrame = frame self.contentOffset = .zero self.frame = CGRect(origin: CGPoint.zero, size: contentSize) UIGraphicsBeginImageContextWithOptions(contentSize, false, UIScreen.main.scale) if let currentContext = UIGraphicsGetCurrentContext() { self.layer.render(in: currentContext) image = UIGraphicsGetImageFromCurrentImageContext() } UIGraphicsEndImageContext() self.contentOffset = formerContentOffset self.frame = formerFrame return image } } private var SwViewCaptureKey_IsCapturing: String = "SwViewCapture_AssoKey_isCapturing" public extension UIView { @objc func swSetFrame(_ frame: CGRect) { // Do nothing, use for swizzling } var isCapturing:Bool! { get { let num = objc_getAssociatedObject(self, &SwViewCaptureKey_IsCapturing) if num == nil { return false } if let numObj = num as? NSNumber { return numObj.boolValue }else { return false } } set(newValue) { let num = NSNumber(value: newValue as Bool) objc_setAssociatedObject(self, &SwViewCaptureKey_IsCapturing, num, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) } } func swCapture(_ completionHandler: (_ capturedImage: UIImage?) -> Void) { self.isCapturing = true let bounds = self.bounds UIGraphicsBeginImageContextWithOptions(bounds.size, false, UIScreen.main.scale) let context = UIGraphicsGetCurrentContext() context?.saveGState() context?.translateBy(x: -self.frame.origin.x, y: -self.frame.origin.y); // if (swContainsWKWebView()) { // self.drawHierarchy(in: bounds, afterScreenUpdates: true) // }else{ self.layer.render(in: context!) // } let capturedImage = UIGraphicsGetImageFromCurrentImageContext() context?.restoreGState(); UIGraphicsEndImageContext() self.isCapturing = false completionHandler(capturedImage) } } extension UIScrollView { public 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!) // 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(self.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. public 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() } } } }