导读:本期聚焦于深圳程序员创作的《如何用Core Graphics绘制iOS股票分时图的渐变填充?三种渐变方式详解》,敬请观看详情。股票分时图下方那层柔和的渐变色是怎么画出来的?本文以Core Graphics为核心,详细介绍线性渐变的三种实现思路:从上到下的纵向渐变、从左到右的横向渐变以及透明度渐变。文章先讲解CGGradient与CGContext的配合原理,再结合分时图价格曲线的Path构建过程,给出可直接使用的Swift代码示例,同时分析每种渐变的适用场景与性能注意事项,帮助你在大批量K线刷新时依然保持流畅的绘制效果。无论你是在做自绘图表还是想深入理解图形上下文,这篇实战内容都值得一读。

做过股票或行情类App的开发者大多遇到过这个需求:分时图的价格曲线下方要铺一层从深到浅的渐变色,让整个图表看起来更有层次感。这层渐变如果用图片切图来做,拉伸后边缘会发虚,而且适配不同屏幕尺寸很麻烦;正确的做法是用Core Graphics在绘制阶段动态生成。本文围绕分时图的渐变填充,讲解从上到下渐变、从左到右渐变和透明度渐变三种实现方式,并给出完整的代码示例。

如何用Core Graphics绘制iOS股票分时图的渐变填充?三种渐变方式详解

一、Core Graphics渐变绘制的基本原理

Core Graphics中绘制渐变主要依赖两个对象:CGContextCGGradient。CGGradient负责描述渐变本身,包括颜色空间、颜色数组以及每个颜色对应的位置参数;CGContext则负责把渐变真正画到画布上。理解这两者的分工,是写好渐变代码的第一步。

创建一个CGGradient需要三个要素:颜色空间通常直接用CGColorSpaceCreateDeviceRGB();颜色数组传入[CGColor];位置数组locations是一个0到1之间的CGFloat数组,0代表渐变起点,1代表终点。如果只传两个颜色,locations可以传nil,系统会自动平均分配。需要注意的是,颜色数量和位置数量必须一致,否则创建会返回nil,这是新手最常踩的坑。

绘制时有两个核心API:drawLinearGradient用于线性渐变,drawRadialGradient用于径向渐变。分时图的填充用线性渐变就足够了。它的参数中的起点和终点决定了渐变的方向:起点终点上下排布就是纵向渐变,左右排布就是横向渐变。另外别忘了给上下文设置裁剪区域,否则渐变会铺满整个画布。

// 在UIView子类的draw(_ rect:)中调用
override func draw(_ rect: CGRect) {
    guard let ctx = UIGraphicsGetCurrentContext() else { return }

    // 颜色空间
    let colorSpace = CGColorSpaceCreateDeviceRGB()
    // 起点颜色:主色,不透明
    let startColor = UIColor(red: 0.2, green: 0.6, blue: 1.0, alpha: 1.0).cgColor
    // 终点颜色:同色系但完全透明
    let endColor = UIColor(red: 0.2, green: 0.6, blue: 1.0, alpha: 0.0).cgColor

    let colors = [startColor, endColor] as CFArray
    let locations: [CGFloat] = [0.0, 1.0]

    guard let gradient = CGGradient(
        colorsSpace: colorSpace,
        colors: colors,
        locations: locations
    ) else { return }

    // 纵向渐变:起点在顶部,终点在同一点的底部
    ctx.drawLinearGradient(
        gradient,
        start: CGPoint(x: 0, y: 0),
        end: CGPoint(x: 0, y: rect.height),
        options: []
    )
}

上面这段代码展示的是最基础的纵向渐变。值得注意的是,drawLinearGradient会从起点到终点做颜色插值,超出范围的部分由options参数决定,默认情况下起点之前填充第一个颜色,终点之后填充最后一个颜色。设置.drawsBeforeStartLocation.drawsAfterEndLocation可以显式控制这个行为,分时图场景下建议保持默认即可。

二、从上到下渐变:分时图填充的主流方案

股票分时图最经典的视觉样式,就是价格曲线下方、从曲线位置往下颜色逐渐变淡,直到底部完全透明。这种效果的实现思路分两步:第一步构建填充区域的闭合路径,也就是价格曲线路径加上右下角、左下角两个点连成的闭合区域;第二步把渐变的起点设在曲线最高处,终点设在图表底部,然后裁剪路径后填充渐变。

构建路径时要注意点的顺序。假设价格数据已经换算成了一组CGPoint,先从第一个点开始用addLines把整条曲线连起来,再依次addLine到右下角和左下角,最后closeSubpath。这样就得到了一个以待绘制曲线为上边缘的闭合区域。裁剪用saveGStateclip的组合,画完之后记得restoreGState,避免裁剪状态污染后续的网格线绘制。

func drawFillGradient(ctx: CGContext, points: [CGPoint], rect: CGRect) {
    guard let first = points.first, let last = points.last else { return }

    // 构建闭合路径:曲线 + 右下 + 左下
    let path = CGMutablePath()
    path.move(to: first)
    path.addLines(between: points)
    path.addLine(to: CGPoint(x: last.x, y: rect.maxY))
    path.addLine(to: CGPoint(x: first.x, y: rect.maxY))
    path.closeSubpath()

    // 保存状态并裁剪
    ctx.saveGState()
    ctx.addPath(path)
    ctx.clip()

    // 从上到下渐变:顶部颜色浓,底部透明
    let colors = [
        UIColor(red: 0.98, green: 0.4, blue: 0.4, alpha: 0.5).cgColor,
        UIColor(red: 0.98, green: 0.4, blue: 0.4, alpha: 0.0).cgColor
    ] as CFArray
    let gradient = CGGradient(
        colorsSpace: CGColorSpaceCreateDeviceRGB(),
        colors: colors,
        locations: [0.0, 1.0]
    )
    if let gradient = gradient {
        ctx.drawLinearGradient(
            gradient,
            start: CGPoint(x: 0, y: rect.minY),
            end: CGPoint(x: 0, y: rect.maxY),
            options: []
        )
    }
    ctx.restoreGState()
}

这种方案的优点是视觉上非常自然,用户的视线会顺着渐变从曲线引导到坐标轴,同时透明度渐弱的效果不会遮挡底部的网格线和时间轴文字。如果想让渐变更细腻,可以在locations里多加几个中间节点,比如[0.0, 0.3, 1.0]配合三个颜色,做出先快速变淡再缓慢消失的层次感。

三、从左到右渐变与透明度渐变的组合运用

从左到右渐变在分时图中也有实际用途。典型场景是竞价阶段和连续交易阶段的区分:图表左侧(早盘集合竞价区)可以用较浅的颜色,随着时间推移颜色逐渐加深,到收盘时最深。实现上只需要把渐变方向的起点和终点改为水平方向即可,其余代码完全复用。

// 横向渐变:从左到右,颜色由浅到深
ctx.drawLinearGradient(
    gradient,
    start: CGPoint(x: rect.minX, y: 0),
    end: CGPoint(x: rect.maxX, y: 0),
    options: []
)

透明度渐变严格来说是前面两种方式的子集——它改变的不是色相而是alpha通道。分时图里最常见的组合是双向透明度渐变:上下方向做透明度衰减的同时,左右两端也做轻微的淡出,让填充区域四边都不生硬。Core Graphics的线性渐变一次只能定义一个方向,要实现双向效果就得画两次:第一次裁剪同一个路径画纵向渐变,第二次叠加画横向渐变,两次叠加的透明度会自然融合。

还有一种做法是用来完成,配置startPointendPoint同样能实现三个方向的渐变,而且它走的是GPU合成,性能通常更好。但它的缺点是mask要靠另一个CAShapeLayer来实现,裁剪精度依赖mask的帧同步,在频繁滚动刷新的实时行情场景下偶尔会出现一帧的错位。所以在自绘图表控件里,个人更推荐纯Core Graphics方案,一次drawRect把曲线、渐变、网格全部画完,绘制结果一致性更好。

四、性能优化与实际项目中的注意事项

分时图是高频刷新的界面,行情推送一般每三秒更新一次,意味着图表每隔几秒就要重绘。这里有几个实践层面的建议。第一,CGGradient对象是只读且可复用的,不要在每次draw(_:)里重新创建,应该把它缓存成属性,只在颜色主题切换时重建。第二,重绘时尽量用setNeedsDisplay(in:)传入脏区域,只重绘新增数据点附近的那一小段,而不是整个view。

第三点关于颜色计算。如果你的渐变颜色需要根据涨跌状态动态变化(涨红跌绿或涨绿跌红),建议提前把UIColor转换成RGBA分量并缓存,避免在绘制循环里反复调用getRed(_:green:blue:alpha:),这个方法在真机上有可测量的开销。第四,对于数据量很大的分时图(比如叠加多日走势),可以考虑把整条填充渐变绘制到CGBitmapContext里缓存成位图,日常刷新只做位图平移加局部重绘,CPU占用会明显下降。

最后提醒一点:模拟器上渐变效果和真机可能有细微色差,特别是带有alpha的低饱和度颜色,在OLED屏幕上会更通透。上线前务必在多台真机上核对渐变的视觉浓度,必要时针对深色模式单独调整颜色数组。Core Graphics的渐变API虽然底层,但只要掌握了路径裁剪和渐变方向的组合技巧,实现主流行情软件那种精致的分时图填充并不困难。

Core Graphics分时图渐变填充修改时间:2026-09-13 12:04:40

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/20260913/55988.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。