123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422 |
- //
- // View+Ex.swift
- // TSLiveWallpaper
- //
- // Created by 100Years on 2024/12/20.
- //
- import UIKit
- public extension UIView {
-
- /// 增加渐变背景,需要先确定当前 view 的 frame
- /// - Parameters:
- /// - colors: 渐变背景颜色数组
- /// - startPoint: 渐变启示位置
- /// - endPoint: 渐变结束位置
- /// - layerSize: 指定 layer 的 size,否则和自己当前一样大
- public func addGradientBg(colors: [CGColor],
- startPoint: CGPoint = .zero,
- endPoint: CGPoint = CGPoint(x: 1, y: 1),
- layerSize: CGSize? = nil) {
- let gl = CAGradientLayer()
- gl.colors = colors
- gl.startPoint = startPoint
- gl.endPoint = endPoint
- gl.frame = CGRect(origin: .zero, size: layerSize ?? self.bounds.size)
- gl.zPosition = -1 // 将 gradientLayer 放在底层
- layer.insertSublayer(gl, at: 0)
- }
-
- /// 慎用
- /// 给 view 增加圆角阴影,会改变视图结构,慎用,
- /// 需add 且确定frame后再调用
- /// > Note: 慎用
- /// - Parameters:
- /// - cornerRadius: 视图圆角
- /// - shadowColor: 阴影颜色
- /// - shadowOffset: 阴影偏移量
- /// - shadowRadius: 阴影扩散距离
- /// - shadowOpacity: 阴影透明度
- @discardableResult
- public func addCornerRadiusShadow(cornerRadius: CGFloat,
- shadowColor: CGColor?,
- shadowOffset: CGSize,
- shadowRadius: CGFloat,
- shadowOpacity: Float) -> UIView? {
- guard let supView = superview else {
- debugPrint("必须要先add,且确定了frame")
- return nil
- }
-
- let frame = self.frame
-
- let shadowView = UIView()
- shadowView.frame = frame
- shadowView.layer.shadowColor = shadowColor
- shadowView.layer.shadowOffset = shadowOffset
- shadowView.layer.shadowOpacity = shadowOpacity
- shadowView.layer.shadowRadius = shadowRadius
-
- supView.insertSubview(shadowView, belowSubview: self)
-
- shadowView.addSubview(self)
- self.frame = CGRect(origin: .zero, size: frame.size)
- self.clipsToBounds = false
- self.layer.masksToBounds = true
- self.layer.cornerRadius = cornerRadius
-
- return shadowView
-
- }
-
-
- /// 给 view 增加阴影
- /// - Parameters:
- /// - cornerRadius: 视图圆角
- /// - shadowColor: 阴影颜色
- /// - shadowOffset: 阴影偏移量
- /// - shadowRadius: 阴影扩散距离
- /// - shadowOpacity: 阴影透明度
- @discardableResult
- public func addShadow(shadowColor: CGColor?,
- shadowOffset: CGSize,
- shadowRadius: CGFloat,
- shadowOpacity: Float){
- layer.shadowColor = shadowColor
- layer.shadowOffset = shadowOffset
- layer.shadowOpacity = shadowOpacity
- layer.shadowRadius = shadowRadius
- }
- }
- public extension UIView {
- public enum MaskContentMode {
- case scaleToFill
- case scaleAspectFit
- case scaleAspectFill
- }
- /// 设置图片蒙版,支持指定 `contentMode` 和缩小比例
- /// - Parameters:
- /// - image: 用作蒙版的图片
- /// - contentMode: 蒙版的内容模式
- /// - scaleFactor: 缩小比例,默认 1.0 表示不缩放,0.8 表示缩小为 80%
- public func setImageMask(image: UIImage, contentMode: MaskContentMode = .scaleAspectFit, scaleFactor: CGFloat = 1.0) {
- guard scaleFactor > 0 && scaleFactor <= 1 else {
- print("Invalid scaleFactor. It must be in the range (0, 1].")
- return
- }
-
- // 创建一个 CALayer 来作为蒙版
- let maskLayer = CALayer()
- maskLayer.contents = image.cgImage
-
- // 计算蒙版的 frame
- let viewSize = self.bounds.size
- let imageSize = image.size
-
- var maskFrame: CGRect = .zero
-
- switch contentMode {
- case .scaleToFill:
- // 拉伸填充整个视图
- maskFrame = CGRect(origin: .zero, size: viewSize)
-
- case .scaleAspectFit:
- // 按比例缩放,适配视图并居中
- let aspectWidth = viewSize.width / imageSize.width
- let aspectHeight = viewSize.height / imageSize.height
- let aspectRatio = min(aspectWidth, aspectHeight) // 按比例适配
-
- let scaledWidth = imageSize.width * aspectRatio * scaleFactor
- let scaledHeight = imageSize.height * aspectRatio * scaleFactor
- let xOffset = (viewSize.width - scaledWidth) / 2
- let yOffset = (viewSize.height - scaledHeight) / 2
-
- maskFrame = CGRect(x: xOffset, y: yOffset, width: scaledWidth, height: scaledHeight)
-
- case .scaleAspectFill:
- // 按比例缩放,填充视图并裁剪多余部分
- let aspectWidth = viewSize.width / imageSize.width
- let aspectHeight = viewSize.height / imageSize.height
- let aspectRatio = max(aspectWidth, aspectHeight) // 按比例填充
-
- let scaledWidth = imageSize.width * aspectRatio * scaleFactor
- let scaledHeight = imageSize.height * aspectRatio * scaleFactor
- let xOffset = (viewSize.width - scaledWidth) / 2
- let yOffset = (viewSize.height - scaledHeight) / 2
-
- maskFrame = CGRect(x: xOffset, y: yOffset, width: scaledWidth, height: scaledHeight)
- }
-
- maskLayer.frame = maskFrame
-
- // 设置蒙版
- self.layer.mask = maskLayer
- }
- }
- // Frame
- public extension UIView {
-
- var viewController: UIViewController? {
- var next = superview
- while next != nil {
- let nextResponder = next?.next
- if nextResponder is UINavigationController ||
- nextResponder is UIViewController {
- return nextResponder as? UIViewController
- }
- next = next?.superview
- }
- return nil
- }
-
- func convertedToImage(rect: CGRect = .zero) -> UIImage? {
- var size = bounds.size
- var origin = bounds.origin
- if !size.equalTo(rect.size) && !rect.isEmpty {
- size = rect.size
- origin = CGPoint(x: -rect.minX, y: -rect.minY)
- }
- let format = UIGraphicsImageRendererFormat()
- format.opaque = false
- format.scale = UIScreen._scale
- let renderer = UIGraphicsImageRenderer(size: size, format: format)
- let image = renderer.image { context in
- drawHierarchy(in: CGRect(origin: origin, size: bounds.size), afterScreenUpdates: true)
- }
- return image
- }
- func toImage() -> UIImage? {
- let renderer = UIGraphicsImageRenderer(bounds: self.bounds)
- let image = renderer.image { context in
- self.layer.render(in: context.cgContext)
- }
- return image
- }
-
- func cornersRound(radius: CGFloat, corner: UIRectCorner) {
- if #available(iOS 11.0, *) {
- layer.cornerRadius = radius
- layer.maskedCorners = corner.mask
- } else {
- let path = UIBezierPath(
- roundedRect: bounds,
- byRoundingCorners: corner,
- cornerRadii: CGSize(width: radius, height: radius)
- )
- let mask = CAShapeLayer()
- mask.path = path.cgPath
- layer.mask = mask
- }
- }
- }
- extension UIRectCorner {
- var mask: CACornerMask {
- switch self {
- case .allCorners:
- return [.layerMinXMinYCorner, .layerMinXMaxYCorner, .layerMaxXMinYCorner, .layerMaxXMaxYCorner]
- default:
- return .init(rawValue: rawValue)
- }
- }
- }
- public extension UIView {
- // 部分圆角(必须Frame已知)
- func makeCorner(_ corners: UIRectCorner, radius: CGFloat) {
- let path = UIBezierPath(roundedRect: bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
- let maskLayer = CAShapeLayer()
- maskLayer.frame = bounds
- maskLayer.path = path.cgPath
- layer.mask = maskLayer
- }
- }
- public extension UIView {
- /// 为视图添加高斯模糊效果
- /// - Parameters:
- /// - blurRadius: 模糊半径(默认 10.0)
- /// - fillColor: 填充颜色(可选,默认透明)
- func applyGaussianBlur(blurRadius: CGFloat = 10.0, fillColor: UIColor? = nil) {
- // 移除已有的模糊效果
- self.removeBlurEffect()
-
- // 创建模糊效果
- let blurEffect = UIBlurEffect(style: .light)
- let blurView = UIVisualEffectView(effect: blurEffect)
- blurView.frame = self.bounds
- blurView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
-
- // 设置模糊强度
- if blurRadius != 10.0 {
- let blurAnimator = CABasicAnimation(keyPath: "inputRadius")
- blurAnimator.fromValue = blurRadius
- blurAnimator.toValue = blurRadius
- blurAnimator.duration = 0
- blurView.layer.add(blurAnimator, forKey: nil)
- }
-
- // 如果指定了填充颜色,添加一个覆盖视图
- if let color = fillColor {
- let colorOverlay = UIView(frame: self.bounds)
- colorOverlay.backgroundColor = color
- colorOverlay.autoresizingMask = [.flexibleWidth, .flexibleHeight]
- colorOverlay.isUserInteractionEnabled = false
- blurView.contentView.addSubview(colorOverlay)
- }
-
- self.addSubview(blurView)
- }
-
- /// 移除模糊效果
- func removeBlurEffect() {
- for subview in subviews {
- if subview is UIVisualEffectView {
- subview.removeFromSuperview()
- }
- }
- }
-
- }
- public extension UIView {
- static func creatColor(color:UIColor) -> UIView {
- let view = UIView()
- view.backgroundColor = color
- return view
- }
- }
- public extension UIView {
- func removeAllSubViews() {
- subviews.forEach { subview in
- subview.removeFromSuperview()
- }
- }
- }
- public func kGetSubFrame(superSize: CGSize, subViewSize: CGSize, contentMode: UIView.ContentMode = .scaleAspectFit, scaleFactor: CGFloat = 1.0)-> CGRect {
- guard scaleFactor > 0 && scaleFactor <= 1 else {
- print("Invalid scaleFactor. It must be in the range (0, 1].")
- return CGRect(origin: .zero, size: superSize)
- }
-
- var maskFrame: CGRect = .zero
- switch contentMode {
- case .scaleToFill:
- // 拉伸填充整个视图
- maskFrame = CGRect(origin: .zero, size: superSize)
-
- case .scaleAspectFit:
- // 按比例缩放,适配视图并居中
- let aspectWidth = superSize.width / subViewSize.width
- let aspectHeight = superSize.height / subViewSize.height
- let aspectRatio = min(aspectWidth, aspectHeight) // 按比例适配
-
- let scaledWidth = subViewSize.width * aspectRatio * scaleFactor
- let scaledHeight = subViewSize.height * aspectRatio * scaleFactor
- let xOffset = (superSize.width - scaledWidth) / 2
- let yOffset = (superSize.height - scaledHeight) / 2
-
- maskFrame = CGRect(x: xOffset, y: yOffset, width: scaledWidth, height: scaledHeight)
-
- case .scaleAspectFill:
- // 按比例缩放,填充视图并裁剪多余部分
- let aspectWidth = superSize.width / subViewSize.width
- let aspectHeight = superSize.height / subViewSize.height
- let aspectRatio = max(aspectWidth, aspectHeight) // 按比例填充
-
- let scaledWidth = subViewSize.width * aspectRatio * scaleFactor
- let scaledHeight = subViewSize.height * aspectRatio * scaleFactor
- let xOffset = (superSize.width - scaledWidth) / 2
- let yOffset = (superSize.height - scaledHeight) / 2
-
- maskFrame = CGRect(x: xOffset, y: yOffset, width: scaledWidth, height: scaledHeight)
- default:
- maskFrame = CGRect(origin: .zero, size: superSize)
- }
-
- return maskFrame
- }
- public extension UIView {
- /// 添加渐变色边框
- /// - Parameters:
- /// - colors: 渐变色数组
- /// - width: 边框宽度
- /// - radius: 圆角半径(nil 时使用视图的现有圆角)
- /// - startPoint: 渐变起点 (默认从左到右)
- /// - endPoint: 渐变终点 (默认从左到右)
- func addGradientBorder(
- colors: [UIColor],
- width: CGFloat = 3,
- radius: CGFloat? = nil,
- startPoint: CGPoint = CGPoint(x: 0, y: 0.5),
- endPoint: CGPoint = CGPoint(x: 1, y: 0.5)
- ) {
- // 移除旧的渐变边框
- removeGradientBorder()
-
- let gradientLayer = CAGradientLayer()
- gradientLayer.name = "GradientBorder"
- gradientLayer.frame = bounds
- gradientLayer.colors = colors.map { $0.cgColor }
- gradientLayer.startPoint = startPoint
- gradientLayer.endPoint = endPoint
-
- let cornerRadius = radius ?? layer.cornerRadius
- let path = UIBezierPath(
- roundedRect: bounds.insetBy(dx: width/2, dy: width/2),
- cornerRadius: cornerRadius
- )
-
- let shapeLayer = CAShapeLayer()
- shapeLayer.name = "GradientBorderMask"
- shapeLayer.path = path.cgPath
- shapeLayer.lineWidth = width
- shapeLayer.fillColor = nil
- shapeLayer.strokeColor = UIColor.black.cgColor
-
- gradientLayer.mask = shapeLayer
- layer.addSublayer(gradientLayer)
- }
-
- /// 更新渐变色边框的frame(在layoutSubviews中调用)
- func updateGradientBorder() {
- guard let gradientLayer = layer.sublayers?.first(where: { $0.name == "GradientBorder" }) as? CAGradientLayer,
- let shapeLayer = gradientLayer.mask as? CAShapeLayer else {
- return
- }
-
- gradientLayer.frame = bounds
-
- let width = shapeLayer.lineWidth
- let cornerRadius = layer.cornerRadius
- let path = UIBezierPath(
- roundedRect: bounds.insetBy(dx: width/2, dy: width/2),
- cornerRadius: cornerRadius
- )
-
- shapeLayer.path = path.cgPath
- }
-
- /// 移除渐变色边框
- func removeGradientBorder() {
- layer.sublayers?.filter { $0.name == "GradientBorder" }.forEach {
- $0.removeFromSuperlayer()
- }
- }
- }
|