UIKit实现一个渐变文字的UILabel(核心思想及实现过程)

一. 引言

在日常开发中渐变背景我们并不陌生,而且官方几乎也给了方案使用CAGradientLayer特殊图层。但是渐变文字呢?这个设计样式不太常见,但是如果是做社交类应用的话,为了凸显用户的身份,会员,贵族等等信息,经常会出现渐变文字甚至是闪烁文字。

提到渐变文字很多人第一反应:

  • 能不能直接给 UILabel 设置渐变色?
  • drawText(in:) 自己画?
  • 或者用图片?

这些方案要么性能一般、要么不够优雅,也不利于组件化复用。

这篇文章我们来实现一个 真正工程可用的渐变文字 UILabel,方案稳定、性能友好,并且可以和常见的渐变按钮、渐变视图保持一致的设计风格。

二. 渐变文字的核心思路

先说结论:

文字本身并不负责显示颜色,颜色来自渐变 Layer;文字只是一个「遮罩(mask)」

整体结构就是:

ZMGradientLabel

└─ CAGradientLayer (真正有颜色)

└─ mask = CATextLayer(文字轮廓)

也就是说:

  • 渐变效果由 CAGradientLayer 提供
  • CATextLayer 只负责定义「文字长什么样」
  • 通过 mask,只显示文字形状区域内的渐变

这是一个 GPU 渲染方案,性能和系统动画完全同级。

三. 渐变文字的具体实现

3.1 定义 ZMGradientLabel

Swift 复制代码
import UIKit

public class ZMGradientLabel: UILabel {

    private let gradientLayer = CAGradientLayer()
    private let textMaskLayer = CATextLayer()

    // MARK: - Init
    public override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }

    public required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }

    private func commonInit() {
        // UILabel 本身不显示颜色
        textColor = .clear

        // 添加渐变 Layer
        layer.addSublayer(gradientLayer)
        gradientLayer.mask = textMaskLayer

        // CATextLayer 基础配置
        textMaskLayer.contentsScale = UIScreen.main.scale
        textMaskLayer.alignmentMode = .center
        textMaskLayer.truncationMode = .end
    }

    // MARK: - Layout
    public override func layoutSubviews() {
        super.layoutSubviews()
        gradientLayer.frame = bounds
        updateTextMask()
    }

    // MARK: - Text 更新
    private func updateTextMask() {
        textMaskLayer.frame = bounds
        textMaskLayer.string = text
        textMaskLayer.font = font
        textMaskLayer.fontSize = font.pointSize
    }

    public override var text: String? {
        didSet { updateTextMask() }
    }

    public override var font: UIFont! {
        didSet { updateTextMask() }
    }
}

到这里,我们已经完成了:

  • 渐变 Layer 的承载
  • 文字作为 Mask 的映射
  • Auto Layout 下的自适应更新

3.2 配置渐变颜色及方向

我们可以为 ZMGradientLabel 添加一个设置颜色及方向方法,来更新它的渐变颜色:

Swift 复制代码
extension ZMGradientLabel {

    public func setupGradient(
        colors: [UIColor],
        locations: [NSNumber]? = nil,
        direction: ZMGradientDirection = .leftToRight
    ) {
        var cgColors = colors.map { $0.cgColor }
        if cgColors.count == 1 {
            cgColors.append(cgColors[0])
        }

        gradientLayer.colors = cgColors
        gradientLayer.locations = locations

        switch direction {
        case .leftToRight:
            gradientLayer.startPoint = CGPoint(x: 0, y: 0.5)
            gradientLayer.endPoint = CGPoint(x: 1, y: 0.5)
        case .rightToLeft:
            gradientLayer.startPoint = CGPoint(x: 1, y: 0.5)
            gradientLayer.endPoint = CGPoint(x: 0, y: 0.5)
        case .topToBottom:
            gradientLayer.startPoint = CGPoint(x: 0.5, y: 0)
            gradientLayer.endPoint = CGPoint(x: 0.5, y: 1)
        case .bottomToTop:
            gradientLayer.startPoint = CGPoint(x: 0.5, y: 1)
            gradientLayer.endPoint = CGPoint(x: 0.5, y: 0)
        case .topLeftToBottomRight:
            gradientLayer.startPoint = CGPoint(x: 0, y: 0)
            gradientLayer.endPoint = CGPoint(x: 1, y: 1)
        case .bottomLeftToTopRight:
            gradientLayer.startPoint = CGPoint(x: 0, y: 1)
            gradientLayer.endPoint = CGPoint(x: 1, y: 0)
        }
    }
}

其中ZMGradientDirection 是我们自定义的枚举。

3.3 使用渐变文字

在使用时,就和普通的UILabel一样设置内容,设置字体,只是在需要渐变时,调用setupGradient方法来设置它的渐变颜色和方向。

Swift 复制代码
let label = ZMGradientLabel()
label.text = "渐变文字"
label.font = .boldSystemFont(ofSize: 20)

label.setupGradient(
    colors: [.systemPink, .systemOrange],
    direction: .leftToRight
)

支持特性:

  • Auto Layout / SnapKit
  • 动态修改 text / font
  • GPU 渲染,性能稳定

四. 结语

渐变文字看起来是一个「视觉需求」,但背后其实是一个非常典型的 Layer + Mask 应用场景。

相比 drawText 或图片方案,CAGradientLayer + CATextLayer

  • 性能更好(GPU 渲染)
  • 更易复用、易扩展
  • 更符合 UIKit 的底层设计哲学

当你已经有了渐变按钮、渐变背景时,把渐变文字也纳入同一套组件体系,会让整个 UI 在一致性和可维护性上都提升一个层级。

相关推荐
程序员黑豆7 小时前
鸿蒙应用开发:Grid组件实现九宫格布局教程
前端·华为·harmonyos
浮江雾7 小时前
Flutter第十七节-----路由管理(3)
android·开发语言·前端·javascript·flutter·入门
阿懂在掘金7 小时前
企业级命令式弹窗方案:三行代码适配已有 Dialog
前端·vue.js·前端框架
Revolution617 小时前
测试接口为什么进了生产包:前端环境变量到底在什么时候生效
前端·前端工程化
午安~婉7 小时前
Git中SSH连接
前端·git·gitee
盏灯7 小时前
mac 外接磁盘,热更新失效
前端·后端
那些年丶ny7 小时前
颜色扩展库
前端·javascript·数据可视化
ihuyigui7 小时前
海外签收通知短信接口
android·java·开发语言·前端·数据库·后端
YWL8 小时前
OpenLayers + Vue 2 使用指南(01)
前端·javascript·vue.js
暖和_白开水8 小时前
数据分析agent (七):contextvars 模块上下文request_id
java·前端·数据分析