// // UIView+Ext.swift // DouYinSwift5 // // Created by lym on 2020/7/23. // Copyright © 2020 lym. All rights reserved. // import UIKit public func adaptWidth(designWidth: CGFloat = 375.0, _ vale: CGFloat) -> CGFloat { return UIScreen.main.bounds.size.width / designWidth * vale } // MARK: - 属性 @objc extension UIView { /// 边框颜色 @IBInspectable var borderColor: UIColor? { get { guard let color = layer.borderColor else { return nil } return UIColor(cgColor: color) } set { guard let color = newValue else { layer.borderColor = nil return } layer.borderColor = color.cgColor } } /// 边框宽度 @IBInspectable var borderWidth: CGFloat { get { return layer.borderWidth } set { layer.borderWidth = newValue } } /// 圆角半径 @IBInspectable var cornerRadius: CGFloat { get { return layer.cornerRadius } set { layer.cornerRadius = newValue layer.masksToBounds = true } } var size: CGSize { get { return frame.size } set { width = newValue.width; height = newValue.height } } var width: CGFloat { get { return frame.size.width } set { return frame.size.width = newValue } } var height: CGFloat { get { return frame.size.height } set { return frame.size.height = newValue } } var x: CGFloat { get { return frame.origin.x } set { frame.origin.x = newValue } } var y: CGFloat { get { return frame.origin.y } set { frame.origin.y = newValue } } var centerX: CGFloat { get { return center.x } set { center.x = newValue } } var centerY: CGFloat { get { return center.y } set { center.y = newValue } } var origin: CGPoint { get { return frame.origin } set { frame.origin = newValue } } } @objc public extension UIView { /// 删除所有的子视图 func removeSubviews() { subviews.forEach { $0.removeFromSuperview() } } /// 添加阴影 /// - Parameters: /// - color: 颜色 /// - radius: 半径 /// - offset: 偏移 /// - opacity: 透明度 func addShadow(ofColor color: UIColor = UIColor(red: 0.07, green: 0.47, blue: 0.57, alpha: 1.0), radius: CGFloat = 3, offset: CGSize = .zero, opacity: Float = 0.5) { layer.shadowColor = color.cgColor layer.shadowOffset = offset layer.shadowRadius = radius layer.shadowOpacity = opacity layer.masksToBounds = false } /// 返回视图的控制器对象 /// /// - Returns: 控制器对象,可能为空 func viewController() -> UIViewController? { var view: UIView? = self repeat { if let nextResponder = view?.next { if nextResponder.isKind(of: UIViewController.self) { return nextResponder as? UIViewController } } view = view?.superview } while view != nil return nil } } @objc extension UIView { @discardableResult /// 添加渐变背景 func addGradientColor(startPoint: CGPoint, endPoint: CGPoint, locs: [NSNumber] = [0, 1], colors: [Any], cornerRadius: CGFloat = 0) -> CAGradientLayer? { 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 nil } layoutIfNeeded() var gradientLayer: CAGradientLayer! removeGradientLayer() gradientLayer = CAGradientLayer() gradientLayer.frame = layer.bounds gradientLayer.startPoint = startPoint gradientLayer.endPoint = endPoint gradientLayer.colors = colors gradientLayer.cornerRadius = layer.cornerRadius gradientLayer.masksToBounds = true gradientLayer.locations = locs if cornerRadius > 0 { let shapeLayer = CAShapeLayer() shapeLayer.borderWidth = 1 shapeLayer.path = UIBezierPath(roundedRect: gradientLayer.bounds, cornerRadius: cornerRadius).cgPath shapeLayer.fillColor = UIColor.clear.cgColor // 必须要设置成clearColor或者nil,默认是黑色 shapeLayer.strokeColor = UIColor.white.cgColor // 随便设置一个非clearColor的颜色 gradientLayer.mask = shapeLayer } // 渐变图层插入到最底层,避免在uibutton上遮盖文字图片 layer.insertSublayer(gradientLayer, at: 0) backgroundColor = UIColor.clear // self如果是UILabel,masksToBounds设为true会导致文字消失 // layer.masksToBounds = false return gradientLayer } public func removeGradientLayer() { if let sl = layer.sublayers { for layer in sl { if layer.isKind(of: CAGradientLayer.self) { layer.removeFromSuperlayer() } } } } func addDashedBorder(to view: UIView, lineLength: CGFloat = 8, lineSpacing: CGFloat = 2, cornerRadius: CGFloat = 0) { let shapeLayer = CAShapeLayer() shapeLayer.name = "DashedBorder" let lineColor = UIColor.c.con // let lineColor = UIColor.red shapeLayer.bounds = view.bounds shapeLayer.position = CGPoint(x: view.bounds.width / 2, y: view.bounds.height / 2) shapeLayer.fillColor = UIColor.clear.cgColor shapeLayer.strokeColor = lineColor.cgColor shapeLayer.lineWidth = 1 shapeLayer.lineJoin = .round shapeLayer.lineDashPattern = [NSNumber(value: Float(lineLength)), NSNumber(value: Float(lineSpacing))] let path = UIBezierPath(roundedRect: view.bounds, cornerRadius: cornerRadius) shapeLayer.path = path.cgPath // 先移除旧的虚线层(避免重复添加) view.layer.sublayers?.removeAll(where: { $0.name == "DashedBorder" }) view.layer.addSublayer(shapeLayer) } } extension UIView{ /// 将一个矩形区域从指定视图坐标系转换到当前视图或窗口坐标系 /// /// 使用方法: /// ``` /// CGRect rect = [self.view convertRect:_button.frame fromViewOrWindow:_button.superview]; /// ``` /// /// button的frame是相对于其superview来确定的,frame确定了button在其superview的位置和大小 /// /// 一般来说,toView方法中,消息的接收者为被转换的frame所在的控件的superview;fromView方法中,消息的接收者为即将转到的目标view. /// /// - Parameters: /// - rect: 矩形区域 /// - view: 指定视图或窗口 /// - Returns: 当前坐标系的矩形区域 func convertRect(rect: CGRect, fromViewOrWindow view: UIView?) -> CGRect { guard let view = view else { if isKind(of: UIWindow.self) { return (self as! UIWindow).convert(rect, from: nil) } else { return convert(rect, from: nil) } } if let from = view.isKind(of: UIWindow.self) ? (view as! UIWindow) : view.window, let to = isKind(of: UIWindow.self) ? (self as! UIWindow) : window, from != to { var r = rect r = from.convert(r, from: view) r = to.convert(r, from: from) r = convert(r, from: to) return r } else { return convert(rect, from: view) } } } extension UIView{ /// 扩展UIView增加抖动方法 /// /// - Parameters: /// - isVertical: 抖动方向(默认是水平方向) /// - times: 抖动次数(默认5次) /// - interval: 每次抖动时间(默认0.1秒) /// - delta: 抖动偏移量(默认2) /// - completion: 抖动动画结束后的回调 public func shake(_ isVertical: Bool = false, _ times: Int = 5, _ interval: TimeInterval = 0.1, _ delta: CGFloat = 2, _ completion: (() -> ())? = nil) { // 播放动画 UIView.animate(withDuration: interval) { var transform = CGAffineTransform(translationX: 0, y: delta) if isVertical == true { transform = CGAffineTransform(translationX: delta, y: 0) } self.layer.setAffineTransform(transform) } completion: {_ in // 如果当前是最后一次抖动,则将位置还原,并调用完成回调函数 if (times == 0) { UIView.animate(withDuration: interval) { self.layer.setAffineTransform(CGAffineTransform.identity) } completion: { _ in completion?() } }else { // 如果当前不是最后一次抖动,则继续播放动画(总次数减1,偏移位置变成相反的) self.shake(isVertical, times - 1, interval, -delta, completion) } } } } extension UIView { //将当前视图转为UIImage func asImage() -> UIImage { let renderer = UIGraphicsImageRenderer(bounds: bounds) return renderer.image { rendererContext in layer.render(in: rendererContext.cgContext) } } /// 获取视图在屏幕上的绝对坐标(相对于整个屏幕) var screenRect: CGRect? { guard let window = self.window else { return nil } return self.superview?.convert(self.frame, to: window) } }