由于项目中有表格统计,所以研究了MPAndroidChart这个库,这算是比较全的一个图表类库,再次感谢作者,膜拜。
关于基础设置的部分网上资料也比较多,所以我主要讲的是自己遇到的需求及问题,不过前期对API也熟悉了一番,不知道的也可以留言,嘿嘿嘿。
下面进去正题,先来看需求:
需求一:
柱状图有渐变色,如下:在网上找资料,查源代码半天,并没有可以设置的API,心死了一半,这不是难为我这样的小白么,呜呜呜。
image功夫不负有心人,经过一番探索,在网上找到了个类似需求的,帮我顺利找到了修改源码的地方,在此感谢。接下来就是简单的自定义了,加油吧少年,哈哈。步骤如下:
1 . 自定义两个类分别继承BarChart和BarChartRenderer
public class MyBarChartRender extends BarChartRenderer {
private RectF mBarShadowRectBuffer = new RectF();
public MyBarChartRender(BarDataProvider chart, ChartAnimator animator,
ViewPortHandler viewPortHandler) {
super(chart, animator, viewPortHandler);
this.mChart = chart;
mHighlightPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mHighlightPaint.setStyle(Paint.Style.FILL);
mHighlightPaint.setColor(Color.rgb(0, 0, 0));
// set alpha after color
mHighlightPaint.setAlpha(120);
mShadowPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mShadowPaint.setStyle(Paint.Style.FILL);
mBarBorderPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mBarBorderPaint.setStyle(Paint.Style.STROKE);
}
protected void drawDataSet(Canvas c, IBarDataSet dataSet, int index) {
Transformer trans = mChart.getTransformer(dataSet.getAxisDependency());
mBarBorderPaint.setColor(dataSet.getBarBorderColor());
mBarBorderPaint.setStrokeWidth(Utils.convertDpToPixel(dataSet.getBarBorderWidth()));
final boolean drawBorder = dataSet.getBarBorderWidth() > 0.f;
float phaseX = mAnimator.getPhaseX();
float phaseY = mAnimator.getPhaseY();
// draw the bar shadow before the values
if (mChart.isDrawBarShadowEnabled()) {
mShadowPaint.setColor(dataSet.getBarShadowColor());
BarData barData = mChart.getBarData();
final float barWidth = barData.getBarWidth();
final float barWidthHalf = barWidth / 2.0f;
float x;
for (int i = 0, count = Math.min((int)(Math.ceil((float)(dataSet.getEntryCount()) * phaseX)), dataSet.getEntryCount());
i < count;
i++) {
BarEntry e = dataSet.getEntryForIndex(i);
x = e.getX();
mBarShadowRectBuffer.left = x - barWidthHalf;
mBarShadowRectBuffer.right = x + barWidthHalf;
trans.rectValueToPixel(mBarShadowRectBuffer);
if (!mViewPortHandler.isInBoundsLeft(mBarShadowRectBuffer.right))
continue;
if (!mViewPortHandler.isInBoundsRight(mBarShadowRectBuffer.left))
break;
mBarShadowRectBuffer.top = mViewPortHandler.contentTop();
mBarShadowRectBuffer.bottom = mViewPortHandler.contentBottom();
c.drawRect(mBarShadowRectBuffer, mShadowPaint);
}
}
// initialize the buffer
BarBuffer buffer = mBarBuffers[index];
buffer.setPhases(phaseX, phaseY);
buffer.setDataSet(index);
buffer.setInverted(mChart.isInverted(dataSet.getAxisDependency()));
buffer.setBarWidth(mChart.getBarData().getBarWidth());
buffer.feed(dataSet);
trans.pointValuesToPixel(buffer.buffer);
final boolean isSingleColor = dataSet.getColors().size() == 1;
if (isSingleColor) {
//mRenderPaint.setColor(dataSet.getColor());
}
for (int j = 0; j < buffer.size(); j += 4) {
if (!mViewPortHandler.isInBoundsLeft(buffer.buffer[j + 2]))
continue;
if (!mViewPortHandler.isInBoundsRight(buffer.buffer[j]))
break;
//以下是主要代码,设置渐变柱状图,当柱状图设置为一种颜色时并不起作用,所以可以手动设置多种颜 色,而显示仍是以下面设置的渐变阴影色为主
if (!isSingleColor) {
//float xValue = dataSet.getEntryForIndex(j/4).getX();
Shader shader = new LinearGradient(0, buffer.buffer[j+1], 0, buffer.buffer[j+3], Color.parseColor("#7dc7fc"),
Color.parseColor("#79a9fd"), Shader.TileMode.CLAMP);
mRenderPaint.setShader(shader);
//mRenderPaint.setColor(dataSet.getColor(j / 4));
}
c.drawRect(buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2],
buffer.buffer[j + 3], mRenderPaint);
}
}
}
public class MyBarChart extends BarChart {
public MyBarChart(Context context) {
super(context);
}
public MyBarChart(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyBarChart(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected void init() {
super.init();
mRenderer = new MyBarChartRender(this, mAnimator, mViewPortHandler);
}
PointF downPoint = new PointF();
//为解决和viewpager滑动冲突,将viewpager滑动范围缩小
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
downPoint.x = event.getX();
downPoint.y = event.getY();
break;
case MotionEvent.ACTION_MOVE:
//通知父控件不要拦截我自己的事件
getParent().requestDisallowInterceptTouchEvent(true);
break;
}
return super.onTouchEvent(event);
}
}
至此第一个需求算是基本解决吧,不过圆角的效果并没有实现。试着将画笔改为圆滑后,数值显示会有问题,所以放弃了圆角
需求二:
直接上图:
捕获.PNG
针对LineChart,虽然支持高亮点击显示,但似乎并不知道点击的时候连接点也做相应变化,于是又开始了自定义之路。。
自定义MyLineChart继承LineChart,MyLineChartRender继承LineChartRenderer:
public class MyLineChart extends LineChart {
public MyLineChart(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public MyLineChart(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyLineChart(Context context) {
super(context);
}
@Override
protected void drawMarkers(Canvas canvas) {
// if there is no marker view or drawing marker is disabled
if (mMarker == null || !isDrawMarkersEnabled() || !valuesToHighlight())
return;
for (int i = 0; i < mIndicesToHighlight.length; i++) {
Highlight highlight = mIndicesToHighlight[i];
IDataSet set = mData.getDataSetByIndex(highlight.getDataSetIndex());
Entry e = mData.getEntryForHighlight(mIndicesToHighlight[i]);
int entryIndex = set.getEntryIndex(e);
// make sure entry not null
if (e == null || entryIndex > set.getEntryCount() * mAnimator.getPhaseX())
continue;
float[] pos = getMarkerPosition(highlight);
//自定义部分,在高亮时画环形,表示选中
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);//画笔为填充模式
paint.setAntiAlias(true);//消除锯齿,使更光滑
paint.setStrokeWidth(5);
int innerRaduis = 16;//内圆半径
int ringWidth = 16;//圆环宽度
// check bounds这句是检查边界的,必须写在paint画圆之上,否则圆过边界不消失
if (!mViewPortHandler.isInBounds(pos[0], pos[1]))
continue;
//画最外层紫色圆
paint.setColor(getResources().getColor(R.color.form_purple));
canvas.drawCircle(pos[0], pos[1], innerRaduis+ringWidth, paint);
//画中间白色露出本分环
paint.setColor(getResources().getColor(R.color.white_fff));
canvas.drawCircle(pos[0], pos[1], innerRaduis+ringWidth/2, paint);
//画内圆
paint.setColor(getResources().getColor(R.color.form_purple));
canvas.drawCircle(pos[0], pos[1],innerRaduis+2 , paint);
// callbacks to update the content
mMarker.refreshContent(e, highlight);
// draw the marker
mMarker.draw(canvas, pos[0], pos[1]);
}
}
@Override
protected void init() {
super.init();
mRenderer = new MyLineChartRender(this, mAnimator, mViewPortHandler);
}
PointF downPoint = new PointF();
//为解决和viewpager滑动冲突,将viewpager滑动范围缩小
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
downPoint.x = event.getX();
downPoint.y = event.getY();
break;
case MotionEvent.ACTION_MOVE:
//通知父控件不要拦截我自己的事件
getParent().requestDisallowInterceptTouchEvent(true);
break;
}
return super.onTouchEvent(event);
}
}
public class MyLineChartRender extends LineChartRenderer{
private Path mHighlightLinePath = new Path();
public MyLineChartRender(LineDataProvider chart, ChartAnimator animator, ViewPortHandler viewPortHandler) {
super(chart, animator, viewPortHandler);
}
@Override
protected void drawHighlightLines(Canvas c, float x, float y, ILineScatterCandleRadarDataSet set) {
// set color and stroke-width
mHighlightPaint.setColor(set.getHighLightColor());
mHighlightPaint.setStrokeWidth(set.getHighlightLineWidth());
// draw highlighted lines (if enabled)
mHighlightPaint.setPathEffect(set.getDashPathEffectHighlight());
// draw vertical highlight lines
if (set.isVerticalHighlightIndicatorEnabled()) {
// create vertical path
mHighlightLinePath.reset();
//自定义高亮指示线,让其不贯穿整个表格,长度为y值得高度
mHighlightLinePath.moveTo(x, y);
//mHighlightLinePath.moveTo(x, mViewPortHandler.contentTop());
mHighlightLinePath.lineTo(x, mViewPortHandler.contentBottom());
c.drawPath(mHighlightLinePath, mHighlightPaint);
}
// draw horizontal highlight lines
if (set.isHorizontalHighlightIndicatorEnabled()) {
// create horizontal path
mHighlightLinePath.reset();
mHighlightLinePath.moveTo(mViewPortHandler.contentLeft(), y);
mHighlightLinePath.lineTo(mViewPortHandler.contentRight(), y);
c.drawPath(mHighlightLinePath, mHighlightPaint);
}
}
}
到此,这两个小需求基本可以凑合看了。不过还有别的问题困扰着我。。。
问题:表格的显示是切换年月的,年月的数据多少不一样,所以需要每次切换数据的时候需要重新设置缩放,并把之前缩放清空最好。
清空缩放:
chart.fitScreen();
设置缩放:
public static void setScale(int size,BarLineChartBase chart){
float radio = size / 6;//6表示当数据比较多的时候一屏显示6个label进行显示
Matrix m = new Matrix();
m.postScale(radio, 1f);//两个参数分别是x,y轴的缩放比例。例如:将x轴的数据放大为之前的几倍
chart.getViewPortHandler().refresh(m, chart, false);//将图表进行缩放
}
这样解决之后,假如我滑动过快,正在拖拽的过程中马上切换年月,重新设置缩放并没有得到执行,所以即使一条数据也有可能要滑半天才能看见。对此,又找到了一对属性:
chart.setDragDecelerationEnabled(true);//设置可以拖拽减速
chart.setDragDecelerationFrictionCoef(0f);//减速速率设置为0,即手指松开马上停止拖拽
这样拖拽的效果可能会比较死板,即手指松开表格就不滑动了,但是可以解决切换数据的问题。所以暂时就如此结尾了。
本人经验有限,有问题的话还请多多指教,感谢阅读。
网友评论