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 在一致性和可维护性上都提升一个层级。

相关推荐
咖啡无伴侣5 小时前
3. 从零搭建企业级 Monorepo 工程化模板:集成 Husky 9 + lint-staged
前端·架构
MetaLite5 小时前
Java通用枚举驱动下拉框-元数据接口与前端契约
java·前端·状态模式
Json____5 小时前
基于 Node + Vue3 的选课管理系统:从教务业务到全栈实践
前端·node·毕设·wwwoop.com
创新技术阁5 小时前
FastapiAdmin 定时任务实现原理与新建任务实操指南
前端·后端·fastapi
3A Cloud5 小时前
Huashu Design:把 AI Agent 变成一间以 HTML 为画布的设计工作室
前端·人工智能·html
你别说话了5 小时前
Webpack 如何迁移重构到 Vite
前端·webpack·重构
catastrophe_zy5 小时前
如何用 WebCodecs 在浏览器里实现高清录屏 —— 无插件、无水印、直接导出 MP4
前端·javascript·录屏
芳心粽伙饭5 小时前
HTML第七章 表格标签
前端·html
我就是DaLing呀!5 小时前
vue3 + 独立的数据管理 Store实现视频剪辑功能
前端·typescript·vue3·canvas·store
吃杠碰小鸡6 小时前
Wps常用功能介绍
前端·wps