【背景】:项目中需要使用到图表,于是找了目前非常热门的开源图表,折线图/柱状图/饼图等应有尽有,各种效果实现都很给力,附上github链接,有原DEMO,github是最好的老师,看DEMO例程源码,相比在网上泛泛的查资料要高效的多。https://github.com/PhilJay/MPAndroidChart
【使用方法】
这里会介绍如何初始化、如何自定义XY坐标轴、如何点击折线图中的数据显示数据标签、如何设置数据。这里仅给出折线图的使用方法,柱状图和饼形图的使用基本类似,在官方GEMO中即可找到,不再赘述了,文末会给出柱状图和饼形图的使用效果展示。
一、折现图的初始化
入参为折线图的对象和自定义的XY坐标轴数据,初始化的相关属性注释中都已给出,这里主要单独说明下如何自定义XY坐标轴、如何点击折线图中的数据显示数据标签。
【定义X坐标轴】
ValueFormatter xAxisFormatter = new LineBarXAxisFormatter(myAxis); //自定义X坐标轴
xAxis.setValueFormatter(xAxisFormatter);
【定义Y坐标轴】
ValueFormatter yAxisFormatter = new LineBarYAxisFormatter("Min"); //自定义Y坐标轴
yAxis.setValueFormatter(yAxisFormatter);
其中LineBarYAxisFormatter 是单独定义的XY坐标轴格式,我们需要单独封装一个类,继承自ValueFormatter,对于X轴,该类的构造函数,创建对象时即输入坐标轴的数据,通过重写方法getFormattedValue方法获取X轴自定义的数据,LineBarXAxisFormatter类定义如下:
/**
* 自定义折线点上的X坐标轴
*/
public class LineBarXAxisFormatter extends ValueFormatter {
private final List mLabels;
/**
* 构造方法,把数据源传进来
* @param labels
*/
public LineBarXAxisFormatter(List labels) {
mLabels = labels;
}
@Override
public String getFormattedValue(float value) {
int v = (int) value;
if(mLabels.size()==1){
return mLabels.get(0).getTime(); //避免当只有一个点时,入参value会出现 -1 0 1 BUG,异常;
}else if (v < mLabels.size() && v >= 0) {
return mLabels.get(v).getTime();
}else{
return null;
}
}
}
对于Y轴,该类的构造函数,创建对象时即输入坐标轴的单位,通过重写方法getFormattedValue方法获取Y轴自定义的数据+单位,如原始数据是10,返回的是10Min,即Y坐标轴显示的是10Min。
//自定义折线点上的Y坐标轴
public class LineBarYAxisFormatter extends ValueFormatter {
private final DecimalFormat mFormat;
private String suffix;
public LineBarYAxisFormatter(String suffix) {
mFormat = new DecimalFormat("0");
this.suffix = suffix;
}
@Override
public String getFormattedValue(float value) {
return mFormat.format(value) + suffix;
}
}
【点击折线图中的数据显示数据标签】
LineBarMarkerView mv = new LineBarMarkerView(this, xAxisFormatter);
mv.setChartView(chart); // For bounds control
chart.setMarker(mv); //设置 marker ,点击后显示的功能 ,布局可以自定义
这里需要自定义LineBarMarkerView类,继承自MarkerView,内部重写refreshContent方法,当点击折线图的值时,就会出现标签,显示想要的数值,具体形式可以自定义,标签显示框布局也可以自定义
//自定义折现点的 值 被点击时,出现的显示框
public class LineBarMarkerView extends MarkerView {
private final TextView tvContent;
private final ValueFormatter xAxisValueFormatter;
private final DecimalFormat format;
public LineBarMarkerView(Context context, ValueFormatter xAxisValueFormatter) {
super(context, R.layout.custom_marker_view);
this.xAxisValueFormatter = xAxisValueFormatter;
tvContent = findViewById(R.id.tvContent); //自定义标签框
format = new DecimalFormat("0");
}
// runs every time the MarkerView is redrawn, can be used to update the
// content (user-interface)
@Override
public void refreshContent(Entry e, Highlight highlight) {
//根据坐标轴数据内容,刷新marker标签显示内容
String x = xAxisValueFormatter.getFormattedValue(e.getX());
String y = Float.toString(e.getY());
tvContent.setText(String.format("x= %s, y= %s", x, y));
super.refreshContent(e, highlight);
}
@Override
public MPPointF getOffset() {
return new MPPointF(-(getWidth() / 2), -getHeight());
}
}
【折线图初始化】
/**初始化折线图
*
* @param chart 图表对象
* @param myAxis XY轴数据
*/
private void InitLineChart(LineChart chart,ArrayList myAxis) {
//设置图表属性
chart.setLogEnabled(false);//打印日志
chart.getDescription().setEnabled(false);//取消描述文字
chart.setNoDataText("没有数据");//没有数据时显示的文字
chart.setNoDataTextColor(Color.WHITE);//没有数据时显示文字的颜色
chart.setDrawGridBackground(false);//chart 绘图区后面的背景矩形将绘制
chart.setDrawBorders(false);//是否禁止绘制图表边框的线
// chart.setBorderColor(Color.WHITE); //设置 chart 边框线的颜色。
// chart.setBorderWidth(3f); //设置 chart 边界线的宽度,单位 dp。
chart.setTouchEnabled(true); //能否点击
chart.setDragEnabled(true); //能否拖拽
chart.setScaleEnabled(true); //能否缩放
chart.setPinchZoom(true); force pinch zoom along both axis
chart.animateX(100);//绘制动画 从左到右
chart.setDoubleTapToZoomEnabled(true);//设置是否可以通过双击屏幕放大图表。默认是true
chart.setHighlightPerDragEnabled(true);//能否拖拽高亮线(数据点与坐标的提示线),默认是true
chart.setDragDecelerationEnabled(true);//拖拽滚动时,手放开是否会持续滚动,默认是true(false是拖到哪是哪,true拖拽之后还会有缓冲)
//设置X坐标轴属性
XAxis xAxis = chart.getXAxis(); //获取x轴线
xAxis.enableGridDashedLine(10f, 10f, 0f);
xAxis.setDrawAxisLine(true);//是否绘制轴线
xAxis.setDrawGridLines(false);//设置x轴上每个点对应的线
xAxis.setDrawLabels(true);//绘制标签 指x轴上的对应数值
xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);//设置x轴的显示位置
xAxis.setGranularity(1); // 让x轴上自定义的值和折线上相对应
// xAxis.setTextSize(12f);//设置文字大小
// xAxis.setTextColor(Color.WHITE);
//设置0-24h时间点
// xAxis.setAxisMinimum(0);//设置x轴的最小值
// xAxis.setAxisMaximum(24);//设置最大值
// xAxis.setLabelCount(12); //设置X轴的显示个数
xAxis.setAvoidFirstLastClipping(true);//图表将避免第一个和最后一个标签条目被减掉在图表或屏幕的边缘
// xAxis.setAxisLineColor(Color.WHITE);//设置x轴线颜色
// xAxis.setAxisLineWidth(0.5f);//设置x轴线宽度
ValueFormatter xAxisFormatter = new LineBarXAxisFormatter(myAxis); //自定义X坐标轴
xAxis.setValueFormatter(xAxisFormatter);
//设置Y坐标轴属性
YAxis yAxis = chart.getAxisLeft();
YAxis axisRight = chart.getAxisRight();
yAxis.enableGridDashedLine(10f, 10f, 0f); //设置Y轴网格线条的虚线,参1 实线长度,参2 虚线长度 ,参3 周期
// yAxis.setGranularity(1); // 网格线条间距
axisRight.setEnabled(false); //设置是否使用 Y轴右边的
yAxis.setEnabled(true); //设置是否使用 Y轴左边的
// yAxis.setGridColor(Color.parseColor("#7189a9")); //网格线条的颜色
yAxis.setDrawLabels(true); //是否显示Y轴刻度
yAxis.setAxisMinimum(0f); //设置Y轴数值 从零开始
// yAxis.setStartAtZero(true); //设置Y轴数值 从零开始
// yAxis.setDrawGridLines(true); //是否使用 Y轴网格线条
// yAxis.setTextSize(12f); //设置Y轴刻度字体
// yAxis.setTextColor(Color.WHITE); //设置字体颜色
// yAxis.setAxisLineColor(Color.WHITE); //设置Y轴颜色
// yAxis.setAxisLineWidth(0.5f);
// yAxis.setDrawAxisLine(true);//是否绘制轴线
// yAxis.setMinWidth(0f);
// yAxis.setMaxWidth(200f);
// yAxis.setDrawGridLines(false);//设置x轴上每个点对应的线
ValueFormatter yAxisFormatter = new LineBarYAxisFormatter("Min"); //自定义Y坐标轴
yAxis.setValueFormatter(yAxisFormatter);
//设置点击折现上的value时出现标签
LineBarMarkerView mv = new LineBarMarkerView(this, xAxisFormatter);
mv.setChartView(chart); // For bounds control
chart.setMarker(mv); //设置 marker ,点击后显示的功能 ,布局可以自定义
// Legend l = chart.getLegend();//图例
// l.setEnabled(true); //是否使用 图例
}
二、折现图设置数据
输入参数为折线图对象和自定义的XY坐标轴,因折线图设置数据需要有固定的格式,MyAndroidChart使用的Entry键值对,xy值都为浮点型数据,所以需要将我们的自定义XY坐标轴数据转化为对应的键值对形式,Entry的x key按序号从0开始递增,y value值即是我们要显示的y轴自定义的数值,实际上在我们上一节定义的X轴类中,可以看到获取X轴数据就是通过0开始的序号对应获取我们自定义的值的。代码如下,其中有一个设置X轴数据显示方向的比较有用,可以避免数据多时重叠不美观,单独提一下:
//设置X轴坐标斜着显示,避免X轴点较多时重合
chart.getXAxis().setLabelRotationAngle(-45);
/**设置折线图数据
*
* @param chart 图表对象
* @param myAxis XY坐标轴数据
*/
private void setLineChartData(LineChart chart,ArrayList myAxis) {
if (myAxis.size() == 0) return;
//填充LineDataSet 所需要的键值对格式
ArrayList mValues =new ArrayList<>();
for (int i = 0; i < myAxis.size(); i++) {
float val = myAxis.get(i).getValue();
mValues.add(new Entry(i,val));
}
LineDataSet set1;
//判断图表中原来是否有数据
if (chart.getData() != null && chart.getData().getDataSetCount() > 0) {
//获取数据1
set1 = (LineDataSet) chart.getData().getDataSetByIndex(0);
set1.setValues(mValues);
//刷新数据
chart.getData().notifyDataChanged();
chart.notifyDataSetChanged();
} else {
//设置数据1 参数1:数据源 参数2:图例名称
set1 = new LineDataSet(mValues, "Time-test");
set1.setMode(LineDataSet.Mode.CUBIC_BEZIER);
set1.setColor(Color.WHITE);
set1.setCircleColor(Color.parseColor("#AAFFFFFF"));
set1.setHighLightColor(Color.WHITE);//设置点击交点后显示交高亮线的颜色
set1.setHighlightEnabled(true);//是否使用点击高亮线
set1.setDrawCircles(true);
set1.setValueTextColor(Color.WHITE);
set1.setLineWidth(1f);//设置线宽
set1.setCircleRadius(2f);//设置焦点圆心的大小
set1.setHighlightLineWidth(0.5f);//设置点击交点后显示高亮线宽
set1.enableDashedHighlightLine(10f, 5f, 0f);//点击后的高亮线的显示样式
set1.setValueTextSize(12f);//设置显示值的文字大小
set1.setDrawFilled(true);//设置使用 范围背景填充
set1.setDrawValues(false);
set1.setFillColor(Color.GREEN);
ArrayList dataSets = new ArrayList<>();
dataSets.add(set1); // add the datasets
//创建LineData对象 属于LineChart折线图的数据集合
LineData data = new LineData(dataSets);
// 添加到图表中
chart.setData(data);
//绘制图表
chart.invalidate();
//设置X轴坐标斜着显示,避免X轴点较多时重合
chart.getXAxis().setLabelRotationAngle(-45);
}
}
三、效果展示
若文章对您有些许帮助,还请您点赞鼓励:),欢迎留言讨论,多谢!