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

使用UIBezierPath实现动画动态折线图 数据更新重绘图层重叠问题咨询

解决方案

你完全不需要更换现有技术栈,只要修复图层未清理的问题即可实现带动画的动态折线图。

问题根源

图层重叠来自两个可修复的逻辑问题:

  • 每次调用drawAnimatedGraph时都会新建CAShapeLayer并添加到视图层级,从未清理旧的动画图层,这些子图层不会随draw(_ rect:)的重绘自动清除
  • 原有draw方法中既通过动画图层渲染折线,又手动调用graphPath.stroke()绘制了静态折线,二者叠加也会加重重叠问题

修改步骤

1. 新增属性存储当前动画图层

在你的自定义折线图View中新增私有属性,持有当前活跃的动画图层,方便后续清理:

private var currentGraphLayer: CAShapeLayer?

2. 优化动画绘制方法

修改drawAnimatedGraph逻辑,每次绘制前先移除旧图层,避免多层叠加,同时补充动画结束后保活的配置:

func drawAnimatedGraph(path: UIBezierPath, _ rect: CGRect) {
    // 移除上一次的旧动画图层
    currentGraphLayer?.removeFromSuperlayer()
    
    let pathLayer = CAShapeLayer()
    pathLayer.frame = self.bounds
    pathLayer.path = path.cgPath
    // 可根据需求修改描边颜色,原有示例的红色和你静态折线的白色冲突,可改为和设计一致的颜色
    pathLayer.strokeColor = UIColor.white.cgColor
    pathLayer.fillColor = nil
    pathLayer.lineWidth = 2.0
    pathLayer.lineJoin = .bevel

    self.layer.addSublayer(pathLayer)
    // 保存新图层的引用
    currentGraphLayer = pathLayer

    let pathAnimation = CABasicAnimation(keyPath: "strokeEnd")
    pathAnimation.duration = 2.0
    pathAnimation.fromValue = 0
    pathAnimation.toValue = 1
    // 配置动画结束后保持最终状态,不会自动消失
    pathAnimation.fillMode = .forwards
    pathAnimation.isRemovedOnCompletion = false
    pathLayer.add(pathAnimation, forKey: "strokeEnd")
}

3. 删除冗余的静态折线绘制

找到draw方法中的graphPath.stroke()这一行代码直接删除,动画图层会负责折线的渲染,不需要重复绘制静态折线。

4. 触发重绘逻辑

每次你更新graphPoints数组(移除首元素+追加新随机数)后,调用setNeedsDisplay()即可触发重绘,不会再出现重叠问题。


原问题重叠效果参考

折线图重叠效果示意


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 03:00:05