MPAndroidChart是Android平台上一款强大易用的图表库,支持线状图、柱状图、散点图等八种图表类型和缩放、拖动(平移)、选择等手势,还支持动画和高亮等功能。但是别人给好的功能毕竟只能满足一般功能,一个程序员最基本的能力就应该是根据需求做出自定义的功能了,这里我对MPAndroidChart进行一些改造,MPAndroidChart只能在节点绘制圆形,现在要给它加上绘制叉号的功能。另外,本来MPAndroidChart的背景只能设置整个一大块背景,现在我加上了按行设置背景色的功能。
效果如图:
节点的细节部分:
功能实现
继承LineChart
自定义LineChart的第一步是要继承LineChart,实现其构造方法。然后重写onDraw方法,在onDraw方法中,再绘制背景,绘制叉号,绘制图表。这里要注意绘制的顺序,从下到上,一层层叠加。
/**
* 重写onDraw方法,注意绘制顺序,先绘制背景色,再绘制叉号,最后绘制图表
* @param canvas
*/
@Override
protected void onDraw(Canvas canvas) {
drawBgColor(canvas);
drawCross(canvas);
super.onDraw(canvas);
Log.i(TAG, "onDraw");
}
画背景
为了让代码看起来更直观,我先创建了一个类BgColor,其中包含start,stop和color三个属性。
/**
* Created by xiaoniu on 2017/4/10.
* BgColor是设置背景的单位,创建时需要传入起点和终点的值,还有要设置的颜色
* 如要把纵坐标20-40的背景设为红色,就新建一个BgColor
* new BgColor(20,40,Color.RED)
*/
public class BgColor {
/**
* @param start 起始点
* @param stop 结束点
* @param color 颜色
*/
public BgColor( float start, float stop,int color) {
this.start = stop;
this.stop = start;
this.color = color;
}
private float start;
private float stop;
private int color;
public float getStart() {
return start;
}
public void setStart(float start) {
this.start = start;
}
public float getStop() {
return stop;
}
public void setStop(float stop) {
this.stop = stop;
}
public int getColor() {
return color;
}
public void setColor(int color) {
this.color = color;
}
}
三个属性分别对应起始点,结束点和颜色。然后将自己需要设置的背景都放到一个List中。
/**
* 分段背景设置
* @return 每条背景的组合
*/
private ArrayList getBg() {
ArrayList bgList = new ArrayList<>();
bgList.add(new BgColor(10, 20, Color.YELLOW));//参数信息:纵坐标从0到20设置颜色为黄色
bgList.add(new BgColor(20, 40, 0xFF00FF00));//支持16进制颜色
bgList.add(new BgColor(40, 70, Color.BLUE));
bgList.add(new BgColor(70, 80, Color.RED));
return bgList;
}
别忘了给图表设置绘制背景的属性,之后再把数据传给图表。
//给表格背景添加颜色
mChart.setDrawBgColor(true);
//设置背景颜色的属性
mChart.setBgColor(getBg());
而在自定义LineChart的drawBgColor方法中,就是从List中取出每个BgColor,获得其start和stop,再根据MPAndroidChart提供的能够将图表上的值转换为像素坐标点的方法getPixelForValues,得到需要绘制背景的左下角和右上角的坐标,用canvas画矩形就可以了。
private void drawBgColor(Canvas canvas) {
if (enableDrawBgColor) {
if (!bgList.isEmpty()) {
Paint paint = new Paint();
for (BgColor r : bgList
) {
MPPointD pStart = this.getPixelForValues(this.getXChartMin(), r.getStart(), YAxis.AxisDependency.LEFT);//左下角
MPPointD pStop = this.getPixelForValues(this.getXChartMax(), r.getStop(), YAxis.AxisDependency.LEFT);//右上角
paint.setColor(r.getColor());
canvas.drawRect(new RectF((float) pStart.x, (float) pStart.y, (float) pStop.x, (float) pStop.y), paint);
}
}else {
Log.i(TAG, "No BgColor to Draw");
}
}
}
画叉号
画叉号之前要得到节点的数据,同样是利用getPixelForValues将图表上的值转化为像素坐标点
private void drawCross(Canvas canvas) {
if (enableDrawCross) {
if (this.getData() != null) {
LineDataSet set = (LineDataSet) this.getData().getDataSetByIndex(0);
list = set.getValues();
set.setDrawCircles(false);
LineData data = new LineData(set);
this.setData(data);
for (Entry e : list
) {
MPPointD p = this.getPixelForValues(e.getX(), e.getY(), YAxis.AxisDependency.LEFT);
drawNode(canvas, (float) p.x, (float) p.y);
}
}else{
Log.i(TAG, "No Data to Draw");
}
}
}
画叉号就是绘制两个互相垂直的直线,有了像素坐标点和canvas也就很简单了。
private void drawNode(Canvas canvas, float x, float y) {
Paint paint = new Paint();
paint.setColor(Color.RED);
paint.setStrokeWidth(crossWidth);
canvas.drawLine(x - crossLength / 2, y - crossLength / 2, x + crossLength / 2, y + crossLength / 2, paint);
canvas.drawLine(x - crossLength / 2, y + crossLength / 2, x + crossLength / 2, y - crossLength / 2, paint);
}
END
细节比较粗糙,以后再完善,欢迎评论交流。
最后附上github代码:https://github.com/xiaoniu/CrossNodeLineChart