CGGradient — 是一个Core Graphics对象,表示两种或多种颜色之间的平滑过渡。与通过循环改变颜色来绘制渐变不同,CGGradient使用硬件加速计算,并支持两种类型:线性(axial)和径向(radial)。根据Apple Documentation(2026),CGGradient用于在iOS和macOS界面中创建逼真的填充、背景效果和模拟光源。
要点
CGGradient — 是Core Graphics中一个不可变对象,封装了一组颜色及其沿渐变过渡的混合规则。在内部,CGGradient存储一个CGColor数组、一个范围[0.0, 1.0]内的位置(locations)数组以及一个指向解释颜色的CGColorSpace的引用。每种颜色都与渐变标度上的一个位置相关联:位置0.0对应开始,1.0对应过渡结束。
通过CGGradientCreateWithColors函数创建CGGradient时,Core Graphics会预先计算颜色的中间值。渐变可以包含任意数量的颜色停止点(color stops),从而可以创建复杂的多色过渡。颜色数量必须至少为两个,并且每种颜色在locations数组中必须有一个对应的位置。
CGGradient的架构与Core Animation中的CAGradientLayer等更高级别的API不同,因为它直接在Core Graphics图形上下文中工作。这提供了对绘制过程的完全控制,以及将渐变与其他Quartz 2D操作(剪贴蒙版、阴影和变换)结合的能力。
Core Graphics支持两种类型的渐变:线性(轴向)和径向(放射状)。线性渐变由CGGradientCreateWithColors函数创建,并通过CGContextDrawLinearGradient绘制。径向渐变需要相同的CGGradient结构,但通过CGContextDrawRadialGradient绘制。
| 类型 | 绘制函数 | 参数 | 应用 |
|---|---|---|---|
| 线性 | CGContextDrawLinearGradient | startPoint, endPoint, options | 背景、按钮、进度条 |
| 径向 | CGContextDrawRadialGradient | startCenter, startRadius, endCenter, endRadius, options | 发光、光源、阴影 |
线性渐变将颜色过渡沿直线从起点startPoint延伸到终点endPoint。颜色在这两点之间进行插值,超出其边界的行为由扩展选项控制。线性渐变非常适合创建平滑的背景、模拟金属表面以及界面元素中的颜色过渡。
径向渐变创建一个圆到另一个圆的颜色过渡。每个圆由中心(startCenter / endCenter)和半径(startRadius / endRadius)定义。颜色从内圆插值到外圆。特殊情况——当起始半径为0时:渐变从一个点扩散开来。径向渐变用于模拟光源、透镜、天体和聚光灯效果。
CGGradient仅由一个基本函数——CGGradientCreateWithColors创建。该函数接受CGColorSpace、CGColor数组(CFArray)和CGFloat locations数组。如果locations为NULL,颜色将均匀分布在渐变标度上。如果指定了locations,其长度必须与颜色数量一致。
locations数组包含从0.0到1.0的值,定义了每种颜色的停止点。这些值必须单调递增。如果第一个值大于0.0,则从开始到此位置的颜色将根据位置0.0的颜色进行外推。对于小于1.0的最后一个值也是如此。此行为由绘制时的扩展选项控制。
选择渐变的颜色时,考虑色彩空间很重要。一个CGGradient中的所有颜色必须属于同一个CGColorSpace——Core Graphics在此空间中对分量进行插值。如果颜色在不同的空间中创建,则需要通过CGColorCreateCopyByMatchingToColorSpace将它们预先转换为同一空间。
Core Graphics提供两个绘制渐变的函数:CGContextDrawLinearGradient用于线性渐变,CGContextDrawRadialGradient用于径向渐变。这两个函数都接受图形上下文、CGGradient对象、扩展选项以及特定于类型的几何参数。绘制时会考虑当前的剪贴蒙版(clip)和上下文变换。
扩展选项控制渐变在0.0–1.0位置范围之外的行为。常量kCGGradientDrawsBeforeStartLocation用第一个停止点的颜色填充起始位置之前的区域。kCGGradientDrawsAfterEndLocation——用最后一个停止点的颜色填充。这些选项可以通过位掩码组合。对于径向渐变,这些选项应用于起始和结束半径之外的区域。
渐变被绘制在当前图形上下文的坐标系中,并考虑其变换(CTM——Current Transformation Matrix)。在调用绘制函数之前应用CGContextTranslateCTM、CGContextScaleCTM或CGContextRotateCTM会改变渐变的位置和比例。这允许将同一个CGGradient重复用于不同区域,而无需创建新对象。
Core Graphics提供了几种额外的渐变管理机制:抗锯齿、通过剪贴蒙版(clipping mask)进行遮罩以及与透明度效果结合。抗锯齿在图形上下文中默认启用,并通过CGContextSetShouldAntialias进行控制。
剪贴蒙版允许将渐变的绘制区域限制为任意形状。在调用CGContextDrawLinearGradient之前,需要通过CGContextBeginPath、CGContextAddPath和CGContextClip定义轮廓。渐变将仅在此轮廓限定的区域内绘制。这广泛用于创建渐变图标、按钮和进度条。
渐变扩展(extend)——另一个重要参数。使用kCGGradientDrawsBeforeStartLocation时,Core Graphics将第一个停止点的颜色外推到直到startPoint的整个区域。如果没有此选项,渐变外部的区域将保持空白(透明)。两个选项的组合确保图形上下文的整个矩形都将被渐变填充,即使startPoint和endPoint位于其内部。
让我们看一下在iOS中使用CGGradient和Core Graphics创建和绘制渐变的实际示例。
该示例创建一个具有三种颜色(蓝色、绿色、红色)的线性渐变,并在UIView的对角线上绘制它。locations数组不均匀地分布颜色:蓝色从0.0到0.3,绿色在0.6处,红色从0.6到1.0。
func drawLinearGradient(in ctx: CGContext,
rect: CGRect) {
let colors = [
UIColor.blue.cgColor,
UIColor.green.cgColor,
UIColor.red.cgColor
] as CFArray
let locations: [CGFloat] = [0.0, 0.6, 1.0]
let space = CGColorSpaceCreateDeviceRGB()
guard let gradient = CGGradientCreateWithColors(
space, colors, locations
) else { return }
let start = CGPoint(x: 0, y: 0)
let end = CGPoint(x: rect.width,
y: rect.height)
ctx.drawLinearGradient(gradient,
start: start, end: end,
options: [.drawsBeforeStartLocation,
.drawsAfterEndLocation])
}
该示例绘制了一个模拟发光的径向渐变。半径为零的起点定义了发光的中心,外圆定义了衰减边界。这种效果用于界面元素的照明或活动指示器。
func drawRadialGlow(in ctx: CGContext,
center: CGPoint) {
let colors = [
UIColor.white.cgColor,
UIColor.orange.cgColor,
UIColor.clear.cgColor
] as CFArray
let locations: [CGFloat] = [0.0, 0.4, 1.0]
let gradient = CGGradientCreateWithColors(
CGColorSpaceCreateDeviceRGB(), colors, locations)
ctx.drawRadialGradient(gradient,
startCenter: center, startRadius: 0,
endCenter: center, endRadius: 100,
options: [.drawsBeforeStartLocation,
.drawsAfterEndLocation])
}
在此示例中,渐变通过剪贴轮廓被限制为圆形区域。在绘制渐变之前,定义了一条圆形路径,该路径成为当前上下文蒙版。渐变仅填充圆内的区域,从而产生渐变图标效果。
func drawGradientInCircle(in ctx: CGContext,
rect: CGRect) {
// 创建圆形剪贴路径
let circlePath = CGMutablePath()
circlePath.addEllipse(in: rect)
ctx.addPath(circlePath)
ctx.clip()
// 在剪贴蒙版内绘制渐变
let colors = [UIColor.magenta.cgColor,
UIColor.cyan.cgColor]
let gradient = CGGradientCreateWithColors(
CGColorSpaceCreateDeviceRGB(),
colors as CFArray, nil)
ctx.drawLinearGradient(gradient,
start: CGPoint(x: 0, y: 0),
end: CGPoint(x: rect.width,
y: rect.height),
options: [.drawsBeforeStartLocation])
}
常见问题
CGGradient — 是一个低级别的Core Graphics对象,用于在图形上下文中绘制。CAGradientLayer — 是一个高级别的Core Animation层,具有自动动画和硬件加速功能。CAGradientLayer对于UIKit来说更易于使用,但CGGradient提供了完全的控制和与任何CGContext的兼容性。
最少数量——2种颜色。上限仅受可用内存限制,因为Core Graphics会存储颜色数组和预先计算的插值表。实际上,一个渐变中超过10–15种颜色是不必要的——视觉过渡变得与平滑过渡无法区分。
在颜色数组中使用Alpha通道小于1.0的CGColor。例如,带透明度的颜色创建为UIColor(red: 0, green: 0, blue: 1, alpha: 0.5).cgColor。Core Graphics像颜色分量一样插值Alpha通道,从而创建平滑的透明度过渡。
是的,CGGradient是Core Graphics的一部分,在两个平台上都可用:iOS和macOS。在macOS上,渐变通过重写drawRect在任何NSView中绘制。所有函数CGGradientCreateWithColors、CGContextDrawLinearGradient和CGContextDrawRadialGradient在两个平台上都是相同的。
要旋转渐变,请在绘制前对图形上下文应用变换:CGContextRotateCTM(ctx, angle)。渐变的start和end点在变换后于上下文的局部坐标系中设置。或者,可以直接计算旋转后的坐标点,而不改变CTM。
总结
CGContextDrawLinearGradient沿startPoint和endPoint之间的直线绘制CGContextDrawRadialGradient从一个圆到另一个圆绘制我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。