You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

UIBezierPath设置不同填充色失效 实现登山坡度颜色编码图表问题

坡度分段着色图表实现问题及解决方案

我的目标是实现如下所示的图表,不同颜色代表每个路段的坡度/梯度百分比。
参考效果图

问题描述

我之前的代码已经完成了“山脉”轮廓的绘制,现在进一步优化,尝试创建一组代表各颜色段的“区块”,但遇到了颜色显示异常的问题,最初使用的代码如下:

let myBezier = UIBezierPath()
let nextPt = fillSlopes(at: idx)

if idx > 0 {
  let prevPt = fillSlopes(at: idx - 1)
  myBezier.move(to: CGPoint(x: prevPt.x, y: height))
  myBezier.addLine(to: CGPoint(x: prevPt.x, y: prevPt.y))
  myBezier.addLine(to: CGPoint(x: nextPt.x, y: nextPt.y))
  myBezier.addLine(to: CGPoint(x: nextPt.x, y: height))
  myBezier.addLine(to: CGPoint(x: prevPt.x, y: height))

  myBezier.close()
  // 测试代码,实际代码会对比数组中存储的当前坡度百分比,根据数值切换对应颜色
  if idx % 2 == 0 {
    UIColor.systemRed.setFill()
    myBezier.fill()
  } else {
    UIColor.systemBlue.setFill()
    myBezier.fill()
  }
}

除了颜色异常问题,我还发现绘制大量小区块会消耗很多CPU资源,希望能得到更优的实现方案。

问题根因

经过排查,问题出在UIBezierPath实例的声明位置:最初将let myBezier = UIBezierPath()写在了for循环外部,所有循环迭代共用同一个路径实例,最终导致[UIBezierPath]数组数据错乱,颜色显示异常。
错误写法示例:

func xxx { 
  let myBezier = UIBezierPath() // 此处为错误写法,所有循环共用同一路径实例
      
  for idx in slopeBars.indices { 
      // 逻辑处理
  }
}

修复方案

将UIBezierPath实例的声明移至for循环内部,每次迭代生成独立的路径实例,同时将路径和对应颜色分开存储,最后统一绘制,即可解决颜色异常问题,同时也能优化部分性能:

func xxx { 
  var slopeBars = [UIBezierPath]()
  var slopeBarColorArray = [UIColor]()

  // 第一步:生成所有路径和对应颜色
  for idx in slopeBars.indices { 
    let myBezier = UIBezierPath()  // 移至循环内部,每次生成独立路径
    let nextPt = fillSlopes(at: idx)

    if idx > 0 {
      let prevPt = fillSlopes(at: idx - 1)
      myBezier.move(to: CGPoint(x: prevPt.x, y: height))
      myBezier.addLine(to: CGPoint(x: prevPt.x, y: prevPt.y))
      myBezier.addLine(to: CGPoint(x: nextPt.x, y: nextPt.y))
      myBezier.addLine(to: CGPoint(x: nextPt.x, y: height))
      myBezier.addLine(to: CGPoint(x: prevPt.x, y: height))

      myBezier.close()
      slopeBars.append(myBezier)

      // 根据坡度值存储对应颜色
      if gradient < 0.0 {
        slopeBarColorArray.append(UIColor(cgColor: Consts.elevChart.slope0_0))
      } else if gradient < 4.0 {
        slopeBarColorArray.append(UIColor(cgColor: Consts.elevChart.slope0_4))
      }
    }
  }

  // 第二步:统一绘制所有路径(原代码将这部分写在循环内部会导致重复绘制,大幅浪费性能,需移到外层)
  for i in 0..<slopeBars.count {
    guard !slopeBarColorArray.isEmpty else { break }
    slopeBarColorArray[i].setStroke()
    slopeBarColorArray[i].setFill()
    slopeBars[i].stroke()
    slopeBars[i].fill()
  }
}

最终实现效果如下:
最终效果图

额外性能优化建议

如果坡度段数量非常多,还可以通过以下方式进一步降低CPU消耗:

  • 合并相邻的同色路径,减少填充和描边的调用次数
  • 静态场景下将绘制结果预渲染为UIImage缓存,后续直接展示缓存图片,不需要每次重绘
  • 改用CGGradient配合路径裁剪实现分段着色,不需要拆分大量小路径,性能提升更明显

内容的提问来源于stack exchange,提问作者app4g

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 08:00:02