为啥说是通用的呢?因为你可以随便放几条折线都行,随便几个说明背景都可以。。。颜色神马都可设置。。。
为啥这么随便?因为公司业务需要,有的折线图是2条折线、2个说明背景色块,有的需要1条折线、3个说明背景,还有个奇葩的是1条折线、4个说明背景,总不能每个都要写一个自定义View吧~
先看效果图:这是两条折线,两个背景图的(拍照不是截图,所以看起来没那么工整,数据我都对比过了,准的一塌糊涂!!!)
先想想思路,一个趋势图需要有以下6个元素:
1,横轴集合 ; 2,纵轴集合; 3,横轴的单位;4,纵轴的单位;5,数据点集合,多少条折线就多少集合;6,说明背景集合。
然后慢慢实现:
写一个表示折线的类:
public class CurveModel {
//坐标点列表
private List<Value> curveLineDataList;
//折线颜色
private int curveColor;
//折线描述语句
private String curveDesc;
public CurveModel(List<Value> curveLineDataList, int curveColor, String curveDesc) {
this.curveLineDataList = curveLineDataList;
this.curveColor = curveColor;
this.curveDesc = curveDesc;
}
...这儿是get方法...
}
再写一个背景的类:
public class BkgModel {
//背景的最小值和最大值
private Value value;
//背景颜色
private int color;
//背景说明文字
private String desc;
public BkgModel(Value value, int color, String desc) {
this.value = value;
this.color = color;
this.desc = desc;
}
...这儿是get方法...
}
Value 类在CurveModel 类中表示x、y的数据,在BkgModel 类表示最小值和最大值
public class Value {
private int x;
private int y;
public Value(int x, int y) {
this.x = x;
this.y = y;
}
...这儿是get方法...
}
好了,所有Model都写好了,接下来,就是重头戏:绘制VIew
这儿用到了建造者模式:
先看下使用吧,看,是不是非常简单,这样构造一个View真是太方便了:
curveTrendChartView.Builder(getApplicationContext())
//设置Y轴的数据
.setY("mmHg", xList, 100.00)
//设置X轴的数据
.setX("日期", yList, 10.0)
//添加背景说明色
.addBKG(new BkgModel(new Value(8000, 9000), Color.parseColor("#FFF5EE"), "低压正常范围"))
//再添加背景说明色,如果你还想添加,那就继续add
.addBKG(new BkgModel(new Value(12000, 14000), Color.parseColor("#E0FFFF"), "高压正常范围"))
//添加折线
.addLine(new CurveModel(lowList, Color.parseColor("#006400"), "低压"))
//我还想添加
.addLine(new CurveModel(highList, Color.RED,"高压"))
.build();
接下来是CurveTrendChartView了:
1,主要重写了onDraw方法:
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//绘制背景和说明文字的方法,在该方法初始化了高度的一些变量,所以首先执行该方法
drawDesc(canvas);
//绘制Y坐标
drawYLineText(canvas);
//绘制X坐标
drawXLineText(canvas);
//绘制背景虚线
drawDottedLine(canvas);
//绘制每条折线
drawCurceLine(canvas);
}
2,接下来就是绘制各个模块了,里面对于坐标的绘制真是让我头疼,调了好多次,各种加减乘除,注意,高度是和趋势图相反的:咱们的趋势图是左图,原点在左下。找XY坐标时,要把思想转换为右图,原点在左上。
举例说明:
虚线的高度是这样的:因为要把虚线绘制在中间,所以得加上mYItemHeight / 2,再加上y轴单位和描述框的高度
i * mYItemHeight + mYItemHeight / 2 + mYUnitHeight + descHeight;
点的高度是这样的:因为虚线是在中间绘制的,所以总高度得减去最上虚线的上半部分和最下虚线的下半部分,然后根据比例求坐标点的位置,最后加上那一大串高度
(mYHeight - mYItemHeight)* ((curveLineDataList.get(i).getY() - maxData) / (minData - maxD