如何局部重绘Canvas非矩形区域?Android折线图拖拽圆点重绘问题
全量重绘是否属于不良实践
绝大多数场景下不属于。
Android View渲染本身做了大量底层优化,只要单次onDraw执行耗时低于16ms(对应60fps刷新阈值)就不会出现掉帧问题。如果你的折线图数据点不超过1000个、网格/坐标轴等固定元素数量不多,全量重绘的性能完全足够,而且代码实现最简单、维护成本最低,完全是可行的方案。
行业常规实现方案
根据图表复杂度不同,通常有三类可选方案,推荐按优先级选择:
1. 普通场景首选:全量重绘
直接按常规逻辑实现即可:
- 在
onTouchEvent中实时记录拖拽圆点的当前坐标 - 每次坐标更新后直接调用
invalidate()触发重绘 onDraw方法中先按原有逻辑绘制网格、折线、坐标轴等固定内容,最后根据存储的坐标绘制Drawable圆点
无需做额外优化,90%以上的折线图场景都适用。
2. 复杂图表(数据点过万/自定义元素极多):分层缓存绘制
如果实测全量重绘确实出现掉帧,可以用离屏缓存降低绘制耗时:
- 首次绘制或者图表数据更新时,把所有固定不变的背景内容(网格、折线、坐标轴等)一次性绘制到一个
Bitmap缓存中 - 后续
onDraw执行时,先调用drawBitmap直接绘制缓存好的背景,再绘制上层的拖拽圆点 - 每次拖拽触发重绘时,仅需要多执行一次常量级的Bitmap绘制操作,耗时远低于重新计算绘制所有折线、网格。
3. 极致性能需求:局部重绘
废弃的invalidate(Rect)只是方法重载被替换,Android 28及以上官方推荐用invalidate(int l, int t, int r, int b) 或者 invalidateDirty(Rect dirty, boolean invalidateCache) 实现完全一样的局部重绘能力:
- 每次拖拽圆点时,记录圆点上一次所在的矩形区域,和新位置的矩形区域,把两个区域都传入局部重绘方法标记为脏区
onDraw时系统只会在标记的脏区执行绘制操作,你只需要在脏区内重绘对应位置的背景(用缓存Bitmap的话直接裁剪绘制即可),再绘制新位置的圆点即可,重绘范围最小,性能最优。
内容的提问来源于stack exchange,提问作者sizzlesmcnizzles
相关产品推荐
相关产品推荐

