转自 https://blog.csdn.net/yuguangwu123/article/details/54575631
MPAndroidChart架构分析:
MPChart是github上最受欢迎的一款开源图标控件,可高度定制化。最近项目需求,需要自己造轮子,就在MPChart基础上进行定制。过后感觉比较好用,但是中间也走了些弯路,总结了一下使用方法,分析了下这个开源框架的架构,分享给大家。
有几种集成方式, Gradle dependency (recommended),Maven,jar file only,clone whole repository(因为需要定制,直接在源码里修改)。项目主页https://github.com/PhilJay/MPAndroidChart
丰富多样的图表效果:(单,双,多)折线图,曲线图,饼状图,散点图,柱状图
项目结构:
Charts里放了各种图表的基类,提供图表参数设定入口。
通过获得的对象可设定图标数据集合
是否支持缩放
图标值选择事件监听
对XY轴绘制的定制:刻度值的显示格式,间隔,刻度数目,网格背景
设定图表动画样式
Data里放了各类图表对应的数据初始化集合类:通过使用泛型和通配符对数据集合
通过初始化获得对象可设定绘制图表线、点、圆的半径、对应颜色、显示数据格式,内容。
Renderer(渲染)里放了对各类图标数据集合以及XY轴数据的绘制
Listener里放的是图表的点击、触摸事件的处理。
总的来讲,chart初始化的时候就使用泛型和通配符定义了数据集合,继承图表的基类,为图标的渲染初始化了render,对点击事件注册了监听。用Barchart举个栗子:
继承柱状图折线图的基类BarLineChartBase,限定数据集合为BarData。
BarLineChartBase,因为LineChart、BubbleChart、ScatterChart、CandleChart都是继承自此类,在限定数据集合的时候,使用泛型和通配符参数化类型。
继承图标基类Chart
以BarChart为例:
当新建Barchart对象时,父类Chart的构造函数会调用init(),在Barchart中重载
@Override
protected void init() {
super.init();
mRenderer = new BarChartRenderer(this, mAnimator, mViewPortHandler);
setHighlighter(new BarHighlighter(this));
getXAxis().setSpaceMin(0.5f);
getXAxis().setSpaceMax(0.5f);
}
在此获取柱状图的渲染器mRenderer
继而可以通过Barchart的对象设定柱状图的刻度显示,是否支持点击、拖动、缩放的监听,以及数据集合。
当设定数据集合时,Chart继承自ViewGroup,会调用notifyDataSetChanged()刷新图表,setData(T data)在Chart中的实现:
public void setData(T data) {
mData = data;
mOffsetsCalculated = false;
if (data == null) {
return;
}
// calculate how many digits are needed
setupDefaultFormatter(data.getYMin(), data.getYMax());
for (IDataSet set : mData.getDataSets()) {
if (set.needsFormatter() || set.getValueFormatter() == mDefaultValueFormatter)
set.setValueFormatter(mDefaultValueFormatter);
}
// let the chart know there is new data
notifyDataSetChanged();
}
在继承的子类中重写notifyDataSetChanged(),在BarLineChartBase中,已经初始化图表的数据集合以及设定横纵轴、图表显示参数,在刷新图表时在OnDraw()中调用横纵轴以及图表内容的渲染对象对图标进行绘制。
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
…………
if (mAxisLeft.isEnabled())
mAxisRendererLeft.computeAxis(mAxisLeft.mAxisMinimum, mAxisLeft.mAxisMaximum, mAxisLeft.isInverted());
if (mAxisRight.isEnabled())
mAxisRendererRight.computeAxis(mAxisRight.mAxisMinimum, mAxisRight.mAxisMaximum, mAxisRight.isInverted());
if (mXAxis.isEnabled())
mXAxisRenderer.computeAxis(mXAxis.mAxisMinimum, mXAxis.mAxisMaximum, false);
mXAxisRenderer.renderAxisLine(canvas);
mAxisRendererLeft.renderAxisLine(canvas);
mAxisRendererRight.renderAxisLine(canvas);
if (mAutoScaleMinMaxEnabled) {
autoScale();
}
mXAxisRenderer.renderGridLines(canvas);
mAxisRendererLeft.renderGridLines(canvas);
mAxisRendererRight.renderGridLines(canvas);
…………
//渲染柱状图
mRenderer.drawData(canvas);
…………
mXAxisRenderer.renderAxisLabels(canvas);
mAxisRendererLeft.renderAxisLabels(canvas);
mAxisRendererRight.renderAxisLabels(canvas);
mRenderer.drawValues(canvas);
mLegendRenderer.renderLegend(canvas);
drawDescription(canvas);
drawMarkers(canvas);
}
在渲染器中,以BarChartRenderer图表内容的渲染为例:
@Override
public void drawData(Canvas c) {
BarData barData = mChart.getBarData();
for (int i = 0; i < barData.getDataSetCount(); i++) {
IBarDataSet set = barData.getDataSetByIndex(i);
if (set.isVisible()) {
drawDataSet(c, set, i);
}
}
}
//绘制数据集合
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();
…………
// 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) {
…………
//柱状图柱子绘制
c.drawRect(buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2],
buffer.buffer[j + 3], mRenderPaint);
if (drawBorder) {
c.drawRect(buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2],
buffer.buffer[j + 3], mBarBorderPaint);
}
}
}
BarChart具体使用示例:
贴上代码:
private void initBarchart(){
/**
初始化以后,可以通过对象设置图标的横纵坐标轴的刻度值以及格式,图标背景,是否支持点击事件,缩放等。
**/
barChart = (BarChart)ndViewById(R.id.barchart);
barChart.setMaxVisibleValueCount(60);
//设定图标网格背景
barChart.setDrawGridBackground(false);
//柱状图值显示格式化,可自定义
IAxisValueFormatter xAxisFormatter = new DayAxisValueFormatter(barChart);
//图标X轴自定义,包括X轴位置、刻度值格式、颜色,网格绘制,背景色,刻度数目,最大最小值限定
XAxis xAxis = barChart.getXAxis();
xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
xAxis.setDrawGridLines(false);
xAxis.setGranularity(1f); // only intervals of 1 day
xAxis.setLabelCount(6);
xAxis.setValueFormatter(new IAxisValueFormatter() {
@Override
public String getFormattedValue(float value, AxisBase axis) {
//根据横坐标刻度值来赋值
int location = Float.valueOf(value).intValue();
location=(location>=7?7:location);
if(location>=0&&location<7&&location return xVals[location]; else return ""; } @Override public int getDecimalDigits() { return 0; } }); //图例,对图表颜色种类的注释 barChart.getLegend().setEnabled(false); //是否显示图标的标题 barChart.getDescription().setEnabled(false); //是否支持图标点击、触摸时间 barChart.setTouchEnabled(false); //是否支持拖动 barChart.setDragEnabled(false); //柱状图左侧Y轴描述,同X轴设定方式 YAxis leftAxis = barChart.getAxisLeft(); leftAxis.setValueFormatter(new IAxisValueFormatter() { @Override public String getFormattedValue(float value, AxisBase axis) { return Float.valueOf(value).intValue()>0?Float.valueOf(value).intValue()+"%":"0"; } @Override public int getDecimalDigits() { return 1; } }); leftAxis.setTypeface(Typeface.DEFAULT); leftAxis.setDrawGridLines(true);//是否绘制柱状图纵轴网格线 leftAxis.setSpaceTop(100f); leftAxis.setLabelCount(10);//纵轴刻度数目 leftAxis.setAxisMaximum(100f);//刻度值最大值 leftAxis.setAxisMinimum(0f); //刻度值最小值 leftAxis.setDrawAxisLine(false); leftAxis.setGridColor(getActivity().getResources().getColor(R.color.line_gray));//纵轴网格线背景色 leftAxis.setGridLineWidth(1);//纵轴网格线宽度 //是否绘制右侧纵轴 barChart.getAxisRight().setEnabled(false); //是否支持缩放 barChart.setScaleEnabled(false); barChart.setPinchZoom(false); //当数据列表为空时默认值显示 barChart.setNoDataText(""); } private void setBarchartData(){ for(int i = 1;i<10;i++) list.add(new BarEntry(1,1)); //设定默认值集合 BarDataSet dataSet = new BarDataSet(list,""); dataSet.setHighlightEnabled(false); dataSet.setDrawValues(false);//是否在图表上显示具体值 dataSet.setColors(VORDIPLOM_COLORS);//设定图表数据绘制颜色 //对绘制的值格式化输出 dataSet.setValueFormatter(new IValueFormatter() { @Override public String getFormattedValue(float value, Entry entry, int dataSetIndex, ViewPortHandler viewPortHandler) { DecimalFormat fnum = new DecimalFormat("##0.00"); return fnum.format(maxvalue.get(entry.getX())+1); } }); BarData data = new BarData(dataSet); data.setBarWidth(0.5f); //设定图标数据集合 barChart.setData(data); } 总结: MPAndroidChart支持对图表横纵轴刻度数目,刻度值格式化,图表数据集合颜色,数据格式化,图例说明等高度定制。在现有开放的api上已经能满足大部分定制图表的需求,如果在项目开发过程中有特殊要求需要深度定制,就需要了解这个图标绘制的一个流程还有监听的处理。希望这篇文章能对大家有帮助。
---------------------
作者:yuguangwu123
来源:CSDN
原文:https://blog.csdn.net/yuguangwu123/article/details/54575631
版权声明:本文为博主原创文章,转载请附上博文链接!