您的位置:首页 > 移动开发 > Android开发

Android图表控件MPAndroidChart——源码修改实现曲线图X轴直尺刻度样式

2017-11-15 10:36 1011 查看
相关文章:

Android图表控件MPAndroidChart的简单介绍(MPAndroidChart3.0)

Android图表控件MPAndroidChart——曲线图LineChart的使用(多条曲线)

Android图表控件MPAndroidChart——曲线图LineChart(多条曲线)动态添加数据

Android图表控件MPAndroidChart——柱状图BarChart的使用(多条柱状图)

Android图表控件MPAndroidChart——曲线图+柱状图 CombinedChart的使用 

Android图表控件MPAndroidChart——源码修改实现曲线图X轴直尺刻度样式

MPAndroidChart在github上的地址:https://github.com/PhilJay/MPAndroidChart

最近需要在曲线图表上显示类似直尺的X轴刻度,如下所示



而MPAndroidChart的XY轴确是这样,没有长短刻度

   


没有找到相关方法设置显示类似直尺样式的刻度(若有相关方法可实现,请告诉我),所以只有修改下源码

先上最终效果图,修改源码后得到的效果如下所示



修改源码之前首先自己在View中画出刻度,然后找到X轴的绘制代码,最后将自己写的方法 融入进去就好了

一 .画刻度线

1.画刻度线的方式(多种方式,说下我的方式)

先画一条刻度线,然后平移画布一段距离(即刻度线间的间距),在画短刻度线(坐标轴未变,只是画布位置变了,至使表面上看起来线位置变了)

2.画刻度线

手机坐标轴:



画刻度:

新建MyScaleView 重写 onDraw()方法

public class MyScaleView extends View {
private Paint scalePaint;
public MyScaleView(Context context) {
this(context, null);
}
public MyScaleView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public MyScaleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initPaint();
}
private void initPaint() {
scalePaint = new Paint();
scalePaint.setAntiAlias(true);
scalePaint.setColor(Color.RED);
scalePaint.setStrokeWidth(2);
scalePaint.setStyle(Paint.Style.FILL);
scalePaint.setDither(true);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
drawScale(canvas);
}
private void drawScale(Canvas canvas) {
int scaleGroup = 5;     // 默认1个长刻度间隔4个短刻度,加起来一组5
int mScaleCount = 101;  //刻度的总个数
canvas.save();
int startX = 30;
int startY = 500;   //即在坐标轴(30,500)处开始画刻度线
for (int i = 0; i < mScaleCount; i++) {
canvas.save();  //记录画布状态
canvas.translate(10 * i, 0);    //画布平移,即刻度线的间距
if (i == 0 || i % scaleGroup == 0) {
canvas.drawLine(startX, startY, startX, startY - 20, scalePaint);//画长刻度线
} else {
canvas.drawLine(startX, startY, startX, startY - 10, scalePaint);//画短刻度线
}
canvas.restore();//取出保存的状态
}
canvas.restore();
}
}


最后应用MyScaleView 效果如下



二.MPAndroidChart库中画 X Y 轴刻度线

1.下载源码:https://github.com/PhilJay/MPAndroidChart/releases

点击 Downloads Source code(zip) 我下载的版本为v3.0.2  解压后里面的MPChartLib即为MPAndroidChart库源码

2.寻找X Y轴的绘制类

说下我的思路

首先找到 X轴  XAxis    并没有什么相关绘制代码

接着找到父类  AxisBase  发现 X Y 轴都继承于该类,那肯定和这类相关了



然后发现 AxisBase 类下定义了 相关属性 和 绘制图形相关



沿着 mGridLineWidth 属性找 mGridLineWidth --> getGridLineWidth() --> XAxisRenderer 与 YAxisRenderer 类



那可以确定 绘制X Y轴的类 就是 XAxisRenderer 与 YAxisRenderer 而且在类中找到了对应的方法



3.绘制X轴

观察平常的LineChart折线图,会发现我们需要的长刻度线与 网格线的位置想对应,所以可以模仿着网格线的绘制代码 绘制 刻度线

绘制网格线的源码如下



仿照上述两个方法,编写我们的刻度线绘制方法

首先,支持提供 方法 是否绘制刻度线 仿照 isDrawGridLinesEnabled() 找到其所在位置‘

在package com.github.mikephil.charting.components; AxisBase类中 

我们可以 设置是否绘制刻度线

protected boolean mIsDrawScale = true;

public void setDrawScale(boolean mIsDrawScale) {
this.mIsDrawScale = mIsDrawScale;
}

public boolean isDrawScale() {
return mIsDrawScale;
}

然后回到  package com.github.mikephil.charting.renderer;包下 XAxisRenderer类中编写

public void renderScaleLines(Canvas c) {
if (!mXAxis.isDrawScale() || !mXAxis.isEnabled())
return;
if (mRenderGridLinesBuffer.length != mAxis.mEntryCount * 2) {
mRenderGridLinesBuffer = new float[mXAxis.mEntryCount * 2];
}
float[] positions = mRenderGridLinesBuffer;
for (int i = 0; i < positions.length; i += 2) {
positions[i] = mXAxis.mEntries[i / 2];
positions[i + 1] = mXAxis.mEntries[i / 2];
}
mTrans.pointValuesToPixel(positions); //获得X轴点对应的像素点位置 即坐标系位置
for (int i = 0; i < positions.length - 2; i += 2) {
//计算X轴两个值之间的间距/5   =  画布偏移量 即 刻度间距 还是默认5个刻度一组
float offset = (positions[i + 2] - positions[i]) / 5;
drawScale(c, positions[i], offset);
}
}

protected void drawScale(Canvas canvas, float startX, float offset) {
float topY =  mViewPortHandler.contentTop(); //顶部X轴所在的位置
float bottomY =  mViewPortHandler.contentBottom(); //底部X轴所在的位置
canvas.save();
if (mXAxis.getPosition() == XAxisPosition.BOTTOM) { //X轴位置在下方时
for (int i = 0; i <= 5; i++) {
canvas.save();
canvas.translate(offset * i, 0);
if (i == 0 || i == 5) {
canvas.drawLine(startX, bottomY - 20, startX, bottomY, mAxisLinePaint);//画长刻度线
} else {
canvas.drawLine(startX, bottomY - 10, startX, bottomY, mAxisLinePaint);//画短刻度线
}
canvas.restore();
}
} else if (mXAxis.getPosition() == XAxisPosition.TOP) { //X轴位置在上方时
for (int i = 0; i <= 5; i++) {
canvas.save();
canvas.translate(offset * i, 0);
if (i == 0 || i == 5) {
canvas.drawLine(startX, topY + 20, startX, topY, mAxisLinePaint);//画长刻度线
} else {
canvas.drawLine(startX, topY + 10, startX, topY, mAxisLinePaint);//画短刻度线
}
canvas.restore();
}
} else if (mXAxis.getPosition() == XAxisPosition.BOTH_SIDED) { //上下都有X轴时
for (int i = 0; i <= 5; i++) {
canvas.save();
canvas.translate(offset * i, 0);
if (i == 0 || i == 5) {
//画长刻度线
canvas.drawLine(startX, topY + 20, startX, topY, mAxisLinePaint);//顶部X轴的刻度
canvas.drawLine(startX, bottomY - 20, startX, bottomY, mAxisLinePaint);//底部X轴的刻度
} else {
//画短刻度线
canvas.drawLine(startX, topY + 10, startX, topY, mAxisLinePaint);//顶部X轴的刻度
canvas.drawLine(startX, bottomY - 10, startX, bottomY, mAxisLinePaint);//底部X轴的刻度
}
canvas.restore();
}
}
canvas.restore();
}


写好了在哪里调用呢?

同样点击源码绘制网格线的方法  renderGridLines(Canvas c) 可以查看到 

在 package com.github.mikephil.charting.charts;包下 BarLineChartBase类中 第 210行 调用了 绘制XY轴 网格线 直线 绘制方法

因此我们的方法也应在此被调用

mXAxisRenderer.renderAxisLine(canvas);
mAxisRendererLeft.renderAxisLine(canvas);
mAxisRendererRight.renderAxisLine(canvas);

mXAxisRenderer.renderGridLines(canvas);
mAxisRendererLeft.renderGridLines(canvas);
mAxisRendererRight.renderGridLines(canvas);

/**********上面是源码的 下面是自己的方法***********************/
mXAxisRenderer.renderScaleLines(canvas);


因为在绘制网格线时,使用的 画笔 mAxisLinePaint 是绘制X轴直线的画笔 所以可以保证刻度线的颜色 粗细 与X轴同步

最后的效果



4.绘制Y轴

绘制Y轴与绘制X轴类似

在 package com.github.mikephil.charting.renderer;包下 YAxisRenderer类中

public void renderScaleLines(Canvas c) {
if (!mYAxis.isDrawScale() || !mYAxis.isEnabled())
return;
float[] positions = getTransformedPositions();
//因为 正常情况下 图表坐标轴在 左下方,所以此处 倒序 由下至上 绘制刻度
for (int i = positions.length; i > 2; i -= 2) {
float offset = (positions[i - 1] - positions[i - 3]) / 5; //偏移量
drawScale(c, positions[i - 3], offset);
}
}
protected void drawScale(Canvas canvas, float startY, float offset) {
float leftX = mViewPortHandler.contentLeft(); //Y轴在左边的位置
float rightX = mViewPortHandler.contentRight();//Y轴在右边的位置
canvas.save();
if (mYAxis.getAxisDependency() == AxisDependency.LEFT) { //Y轴位置在左边时
for (int i = 0; i <= 5; i++) {
canvas.save();
canvas.translate(0, offset * i);
if (i == 0 || i == 5) {
canvas.drawLine(leftX, startY, leftX + 20, startY, mAxisLinePaint);//画长刻度线
} else {
canvas.drawLine(leftX, startY, leftX + 10, startY, mAxisLinePaint);//画短刻度线
}
canvas.restore();
}
}
if (mYAxis.getAxisDependency() == AxisDependency.RIGHT) { //Y轴位置在右边时
for (int i = 0; i <= 5; i++) {
canvas.save();
canvas.translate(0, offset * i);
if (i == 0 || i == 5) {
canvas.drawLine(rightX, startY, rightX - 20, startY, mAxisLinePaint);//画长刻度线
} else {
canvas.drawLine(rightX, startY, rightX - 10, startY, mAxisLinePaint);//画短刻度线
}
canvas.restore();
}
}
canvas.restore();
}


然后在 前面调用X轴绘制刻度线的位置 调用绘制Y轴刻度线的方法

mXAxisRenderer.renderScaleLines(canvas);

mAxisRendererLeft.renderScaleLines(canvas);
mAxisRendererRight.renderScaleLines(canvas);


最终效果如文章开始所展示的图

三 总结

观察一下MPAndroidChart 源码的包名 看名字就可以知道功能,需要修改哪些东西就去对应的包下找

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: