Canvas 是 Android 绘图的核心载体,相当于“画布”,所有图形(矩形、线段、路径等)都通过 Canvas 的 API 绘制到 View 上。
一、Canvas 基础认知
1. 核心作用
- 提供各类绘图方法(画矩形、线段、路径、文字等);
- 承载绘图的“图层”,支持平移、缩放、旋转等变换(本文聚焦基础绘制,变换后续扩展);
- 必须在
View.onDraw(Canvas canvas)方法中使用(系统会自动传入 Canvas 对象)。
2. 与 Paint 的关系
- Canvas:“画布”—— 决定“画什么形状”(矩形/线段/路径);
- Paint:“画笔”—— 决定“怎么画”(颜色、粗细、填充/描边、抗锯齿等);
- 核心公式:
Canvas.drawXXX(形状参数, Paint),二者必须配合使用。
二、关键基础:坐标体系
Android 绘图的坐标规则直接影响 K 线图的“价格-像素”映射,必须牢记:
- 原点 (0,0):View 的 左上角;
- X 轴:向右为正方向(符合日常视觉,K 线从左到右排列);
- Y 轴:向下为正方向(与数学坐标系相反!关键区别);
- 例:K 线图中“高价在上、低价在下”,需通过公式转换(如 K 线图中
priceToY方法)。
坐标映射实战(K 线图核心)
K 线图中“价格 → Y 轴像素”的逻辑,正是基于坐标体系设计:
// 价格越高,Y 轴像素值越小(越靠上)
private float priceToY(float price, float height) {
if (mMaxPrice == mMinPrice) return 0;
// 公式逻辑:(最高价 - 当前价) 决定“距离顶部的比例”,再乘以 View 高度
return height * (mMaxPrice - price) / (mMaxPrice - mMinPrice);
}三、K 线图常用 Canvas API(实战重点)
1. 绘制矩形(K 线实体)
用途:绘制 K 线的“开盘价-收盘价”实体部分;
API:
canvas.drawRect(float left, float top, float right, float bottom, Paint paint);参数说明:
left:矩形左边界 X 坐标;top:矩形上边界 Y 坐标(注意:Y 轴向下为正,所以“上方”的 Y 值更小);right:矩形右边界 X 坐标;bottom:矩形下边界 Y 坐标;实战注意:
需确保
top < bottom(K 线实体是有效矩形),所以取open和close对应的 Y 值的 min/max;涨跌幅为 0 时(
top == bottom),强制bottom += 1f,避免矩形消失。
2. 绘制线段(K 线影线)
用途:绘制 K 线的“最高价-最低价”影线(竖线);
API:
canvas.drawLine(float startX, float startY, float endX, float endY, Paint paint);参数说明:
startX/startY:线段起点坐标;endX/endY:线段终点坐标;实战技巧:
K 线影线需“居中”,所以 X 坐标取 K 线的中心线(
xCenter = xLeft + mCandleWidth / 2f);起点是最高价对应的 Y 值(
yHigh,更靠上,Y 更小),终点是最低价对应的 Y 值(yLow,更靠下,Y 更大)。
3. 绘制路径(均线)
- 用途:绘制 MA5/MA10 等连续均线(需连接多个点);
- 核心类:
Path(记录连续的坐标点,形成路径); - 常用 API 组合:
Path.moveTo(float x, float y):设置路径起点(第一个均线点);Path.lineTo(float x, float y):添加路径后续点(后续均线点,自动与上一个点连接);canvas.drawPath(Path path, Paint paint):绘制完整路径;
实战优势:
比循环调用
drawLine更高效(一次性绘制连续线段);路径更顺滑,避免线段断裂(适合均线、趋势线等连续图形)。
4. 绘制背景(基础铺垫)
- 用途:设置 K 线图的黑色背景;
- API:
canvas.drawColor(int color)或canvas.drawARGB(int a, int r, int g, int b); - 注意:需在绘制其他图形前调用(先铺背景,再画前景内容)。
四、Paint 关键配置(影响绘制效果)
K 线图中用到的 Paint 配置,覆盖核心属性:
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); // 抗锯齿(必加,避免图形边缘毛刺)
paint.setColor(Color.RED); // 颜色(涨红跌绿、均线黄/紫)
paint.setStyle(Paint.Style.FILL); // 填充模式(K 线实体用 FILL,均线用 STROKE)
paint.setStyle(Paint.Style.STROKE); // 描边模式(仅画轮廓,适合线段、路径)
paint.setStrokeWidth(2f); // 线条宽度(影线、均线的粗细)关键属性说明:
ANTI_ALIAS_FLAG:抗锯齿,必须开启(否则 K 线、均线边缘会有锯齿,影响视觉);Style:FILL:填充(矩形内部上色,适合 K 线实体);STROKE:仅描边(适合线段、均线,不填充内部);StrokeWidth:线条粗细,数值越大越粗(均线用 3f,影线用 2f,根据需求调整)。
五、K 线图绘制流程(串联 Canvas 核心用法)
- 初始化画布:
canvas.drawColor(Color.BLACK)铺黑色背景; - 计算参数:可视区域 K 线数量、最高价/最低价(适配 Y 轴);
- 绘制 K 线:
- 循环遍历可视区域的 K 线数据;
- 计算每个 K 线的 X 边界(左/右)、Y 坐标(开/收/高/低);
- 用
drawLine画影线,drawRect画实体;
- 绘制均线:
- 用
Path记录所有均线点(moveTo起点 +lineTo后续点); - 用
drawPath一次性绘制 MA5/MA10;
- 刷新画布:通过
invalidate()触发onDraw重绘(手势滑动/缩放后调用)。
六、常见坑与注意事项6
- 坐标计算错误:忘记 Y 轴向下为正,导致价格映射颠倒(高价在下、低价在上);
- 除零错误:计算
priceToY时,需判断mMaxPrice == mMinPrice(避免除零); - 图形超出屏幕:未计算可视区域的最高/最低价,导致 K 线或均线超出 View 范围;
- 绘制顺序:先画背景,再画 K 线,最后画均线(避免被遮挡);
- 性能优化:避免在
onDraw中创建对象(如 Paint、Path),需提前初始化(K 线图中已做到)。