背景色渐变-边框色渐变边框

仅供参考

//MARK: -扩展背景色渐变功能
extension UIView {
    /// 渐变方向枚举
    enum GradientDirection {
        case leftToRight        // 从左到右
        case topToBottom        // 从上到下
        case leftTopToRightBottom // 左上到右下
        case rightTopToLeftBottom // 右上到左下
        case custom(start: CGPoint, end: CGPoint) // 自定义方向
        
        /// 计算属性:返回对应方向的起止点
        var points: (start: CGPoint, end: CGPoint) {
            switch self {
            case .leftToRight:
                return (CGPoint(x: 0, y: 0.5), CGPoint(x: 1, y: 0.5))
            case .topToBottom:
                return (CGPoint(x: 0.5, y: 0), CGPoint(x: 0.5, y: 1))
            case .leftTopToRightBottom:
                return (CGPoint(x: 0, y: 0), CGPoint(x: 1, y: 1))
            case .rightTopToLeftBottom:
                return (CGPoint(x: 1, y: 0), CGPoint(x: 0, y: 1))
            case .custom(let start, let end):
                return (start, end)
            }
        }
    }
    
    /// 设置渐变背景色
    /// - Parameters:
    ///   - colors: 渐变颜色数组
    ///   - direction: 渐变方向,默认从左到右
    ///   - locations: 颜色位置数组,可选
    func addGradientBackground(colors: [UIColor],
                               direction: GradientDirection = .leftToRight,
                               locations: [NSNumber]? = nil) {
        // 移除已有的渐变层
        removeGradientBackground()
        
        // 创建渐变层
        let gradientLayer = CAGradientLayer()
        gradientLayer.name = "GradientBackground" // 设置标识名称
        gradientLayer.frame = bounds
        gradientLayer.colors = colors.map { $0.cgColor }
        
        // 设置渐变方向
        let (startPoint, endPoint) = direction.points
        gradientLayer.startPoint = startPoint
        gradientLayer.endPoint = endPoint
        
        // 设置颜色位置
        if let locations = locations {
            gradientLayer.locations = locations
        }
        
        // 将渐变层插入到最底层
        layer.insertSublayer(gradientLayer, at: 0)
    }
    
    /// 更新渐变背景层的大小
    func updateGradientBackground() {
        guard let gradientLayer = layer.sublayers?
            .first(where: { $0.name == "GradientBackground" }) as? CAGradientLayer else {
            return
        }
        gradientLayer.frame = bounds
    }
    
    /// 移除渐变背景层
    func removeGradientBackground() {
        layer.sublayers?
            .filter { $0.name == "GradientBackground" }
            .forEach { $0.removeFromSuperlayer() }
    }
}

//MARK: -渐变边框扩展实现
extension UIView {

    /// 给 UIView 添加渐变边框
    /// - Parameters:
    ///   - colors: 渐变颜色数组(至少需要2种颜色)
    ///   - direction: 渐变方向,默认为从左到右
    ///   - lineWidth: 边框宽度,默认 1
    ///   - cornerRadius: 圆角半径,默认为视图当前的 `cornerRadius`
    func addGradientBorder(colors: [UIColor],
                           direction: GradientDirection = .leftToRight,
                           lineWidth: CGFloat = 1,
                           cornerRadius: CGFloat? = nil) {
        guard colors.count > 1 else { return } // 至少需要 2 种颜色

        // 移除旧的渐变边框,防止重复添加
        removeGradientBorder()

        let gradientLayer = CAGradientLayer()
        gradientLayer.name = "GradientBorderLayer"
        gradientLayer.colors = colors.map { $0.cgColor }
        let (startPoint, endPoint) = direction.points
        gradientLayer.startPoint = startPoint
        gradientLayer.endPoint = endPoint
        gradientLayer.frame = bounds // 设置初始大小

        // 创建形状层(用于定义边框路径)
        let shapeLayer = CAShapeLayer()
        shapeLayer.lineWidth = lineWidth
        shapeLayer.fillColor = nil
        shapeLayer.strokeColor = UIColor.black.cgColor
        shapeLayer.lineCap = .round

        // 设置圆角(优先使用参数值,否则使用视图当前的圆角)
        let effectiveCornerRadius = cornerRadius ?? layer.cornerRadius
        shapeLayer.path = UIBezierPath(
            roundedRect: bounds.insetBy(dx: lineWidth / 2, dy: lineWidth / 2),
            cornerRadius: effectiveCornerRadius
        ).cgPath

        // 绑定 mask
        gradientLayer.mask = shapeLayer
        layer.addSublayer(gradientLayer)
    }

    /// 移除渐变边框
    func removeGradientBorder() {
        layer.sublayers?.removeAll { $0.name == "GradientBorderLayer" }
    }

    /// 更新渐变边框(在 `layoutSubviews` 里调用)
    func updateGradientBorder() {
        guard let gradientLayer = layer.sublayers?.first(where: { $0.name == "GradientBorderLayer" }) as? CAGradientLayer,
              let shapeLayer = gradientLayer.mask as? CAShapeLayer else {
            return
        }

        // 更新 `frame`
        gradientLayer.frame = bounds

        // 重新计算边框路径
        let lineWidth = shapeLayer.lineWidth
        let cornerRadius = layer.cornerRadius // 使用当前的 `cornerRadius`
        shapeLayer.path = UIBezierPath(
            roundedRect: bounds.insetBy(dx: lineWidth / 2, dy: lineWidth / 2),
            cornerRadius: cornerRadius
        ).cgPath
    }
}
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容