最近闲来无事,总结下Android的MPAndroidChart组件,这个组件对于绘图来说,可以说是非常方便了,本文包括柱形图,折线图,饼状图,动态折线图等的基本使用
首先
首先是导入依赖,除了MPAndroidChart所需的依赖包,我还导入了butterknife的包,可以用于绑定视图;
1.projectde gradle
repositories {
google()
//加上如下
maven { url "https://jitpack.io" }
jcenter()
}
2.module的gradle
在依赖中加入如下,
//MPAndroidChart依赖
implementation 'com.github.PhilJay:MPAndroidChart:v3.0.3'
implementation 'com.jakewharton:butterknife:10.0.0'
annotationProcessor 'com.jakewharton:butterknife-compiler:10.0.0'
必须指定jdk版本,否则编译会报错的
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
在使用的时候必须要先**ButterKnife.bind(this);**绑定这个Activity,然后可以通过@OnClick和@BindView注解绑定视图和事件
动态折线图
先上效果图:
布局文件
**布局文件**
```xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.github.mikephil.charting.charts.LineChart
android:id="@+id/dy_line_chart"
android:layout_width="match_parent"
android:layout_height="400dp"
android:layout_marginTop="50dp"
android:layout_weight="1"/>
</LinearLayout>
图1,通过工具类进行操作,每隔一秒进行插入数据,最多显示10个,当超过十个的时候,x轴会向左偏移,但页面超过10个点的时候可以滑动,查看之前的(没想好如何解决)
图2,通过当数据更新的时候,去刷新页面,实现动态的效果,当超过10的时候,将数据往往前移动一位,重新赋值,保证页面只显示最新的10个点(因为会频繁的创建对象,不知道会不会导致内存溢出)
方式一
所需要的工具类代码:
/**
* 动态折线图工具类
*/
public class DyLineChartUtils {
private LineChart lineChart;
private YAxis leftAxis;
private XAxis xAxis;
private LineData lineData;
private LineDataSet lineDataSet;
private List<String> timeList = new ArrayList<>(); //存储x轴的时间
private Context context;
public DyLineChartUtils(LineChart mLineChart, String name, int color, Context con) {
this.context=con;
this.lineChart = mLineChart;
leftAxis = lineChart.getAxisLeft();
xAxis = lineChart.getXAxis();
initLineChart();
initLineDataSet(name, color);
}
/**
* 初始化LineChart
*/
private void initLineChart() {
lineChart.setDoubleTapToZoomEnabled(false);
// 不显示数据描述
lineChart.getDescription().setEnabled(false);
// 没有数据的时候,显示“暂无数据”
lineChart.setNoDataText("暂无数据");
//禁止x轴y轴同时进行缩放
lineChart.setPinchZoom(false);
//启用/禁用缩放图表上的两个轴。
lineChart.setScaleEnabled(false);
//设置为false以禁止通过在其上双击缩放图表。
lineChart.getAxisRight().setEnabled(false);//关闭右侧Y轴
lineChart.setDrawGridBackground(false);
//显示边界
lineChart.setDrawBorders(true);
//折线图例 标签 设置 这里不显示图例
Legend legend = lineChart.getLegend();
legend.setEnabled(false);
//X轴设置显示位置在底部
xAxis.setEnabled(false);//关闭x轴
xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
xAxis.setGranularity(1f);
xAxis.setLabelCount(10);
xAxis.setDrawGridLines(false); // 不绘制网格线
xAxis.setValueFormatter(new IAxisValueFormatter() {
@Override
public String getFormattedValue(float value, AxisBase axis) {
return "";
}
});
//保证Y轴从0开始,不然会上移一点
leftAxis.setAxisMinimum(0f);
leftAxis.setDrawGridLines(false);
}
/**
* 初始化折线(一条线)
*
* @param name
* @param color
*/
private void initLineDataSet(String name, int color) {
lineDataSet = new LineDataSet(null, name);
lineDataSet.setLineWidth(1.5f);
lineDataSet.setCircleRadius(3f);
lineDataSet.setColor(color);
lineDataSet.setCircleColor(color);
lineDataSet.setHighLightColor(color);
//设置曲线填充
lineDataSet.setDrawFilled(true);//填充底部颜色
lineDataSet.setAxisDependency(YAxis.AxisDependency.LEFT);
lineDataSet.setValueTextSize(10f);
lineDataSet.setMode(LineDataSet.Mode.LINEAR);//CUBIC_BEZIER
//添加一个空的 LineData
lineData = new LineData();
lineChart.setData(lineData);
LineChartMarkView mv = new LineChartMarkView(context, xAxis.getValueFormatter());
mv.setChartView(lineChart);
lineChart.setMarker(mv);
lineChart.invalidate();
}
/**
* 动态添加数据(一条折线图)
*
* @param number
*/
public void addEntry(Double number) {
//最开始的时候才添加 lineDataSet(一个lineDataSet 代表一条线)
if (lineDataSet.getEntryCount() == 0) {
lineData.addDataSet(lineDataSet);
}
lineChart.setData(lineData);
//避免集合数据过多,及时清空(做这样的处理,并不知道有没有用,但还是这样做了)
if (timeList.size() > 11) {
timeList.clear();
}
lineDataSet.setDrawValues(false);//不显示折线上的值
Entry entry = new Entry(lineDataSet.getEntryCount(), number.floatValue());
lineData.addEntry(entry, 0);
//通知数据已经改变
lineData.notifyDataChanged();
lineChart.notifyDataSetChanged();
//设置在曲线图中显示的最大数量
lineChart.setVisibleXRangeMaximum(10);
//移到某个位置
lineChart.moveViewToX(lineData.getEntryCount() - 5);
}
/**
* 设置Y轴值
*/
public void setYAxis(float max, float min, int labelCount) {
if (max < min) {
return;
}
leftAxis.setAxisMaximum(max);
leftAxis.setAxisMinimum(min);
leftAxis.setLabelCount(labelCount, false);
lineChart.invalidate();
}
}
在这里我设置了个markView,当点击折线图的点时,会浮窗显示对应y轴的数据代码很简单:
布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/shape_gary"
android:orientation="vertical">
<TextView
android:id="@+id/tv_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:textColor="@android:color/white" />
</LinearLayout>
java代码:
public class LineChartMarkView extends MarkerView {
private TextView tvValue;
private IAxisValueFormatter xAxisValueFormatter;
public LineChartMarkView(Context context, IAxisValueFormatter xAxisValueFormatter) {
super(context, R.layout.layout_markview);
this.xAxisValueFormatter = xAxisValueFormatter;
tvValue = findViewById(R.id.tv_value);
}
@SuppressLint("SetTextI18n")
@Override
public void refreshContent(Entry e, Highlight highlight) {
super.refreshContent(e, highlight);
tvValue.setText(e.getY()+"");
}
@Override
public MPPointF getOffset() {
return new MPPointF(-(getWidth() / 2), -getHeight());
}
}
剩下的就是调用了,在Activity中直接使用即可
public class DyLineChartActivity extends Activity {
@BindView(R.id.dy_line_chart)
LineChart lineChart;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.mp_dy_line_chart);
ButterKnife.bind(this);
//方式1
initWay1();
//方式2
// initWay2();
}
/**
* 通过工具类,动态添加数据,不断使x轴偏移
*/
public void initWay1(){
//1、创建工具类对象
DyLineChartUtils dy = new DyLineChartUtils(lineChart,"", Color.RED,this);
//2.设置最大值
dy.setYAxis(40,0,5);
//3.添加数据
//死循环查询数据
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
runOnUiThread(new Runnable() {
@Override
public void run() {
double v = (Math.random() * 20) + 20;
dy.addEntry(v);
}
});
}
}
}).start();
}
方式二
方式二是在一的基础上去改的,实现了只保留10条最新的记录
更新下代码,将代码抽出一个工具类,方便使用
/**
* 动态折线图工具类
*/
public class DyLineChartUtils {
LineChart lineChart;
private YAxis yAxis;
private XAxis xAxis;
private List<Entry> entries;
private LineData lineData;
private LineDataSet lineDataSet;
private Context context;
/**
* @param mLineChart chart对象
* @param name 折线名字
* @param color 折线的颜色
* @param mContext
* @param max y轴最大值
* @param min y轴最小值
* @param labelCount 点的个数
*/
public DyLineChartUtils(LineChart mLineChart, String name, int color, Context mContext,float max, float min, int labelCount) {
this.context=mContext;
this.lineChart = mLineChart;
entries=new ArrayList<>();
initLineChart();
setYAxis(max,min,labelCount);
initLineDataSet(name,color);
}
/**
* 通过不断的刷新数据
*/
public void initLineChart(){
//显示边界
lineChart.setDrawBorders(true);
// 不显示数据描述
lineChart.getDescription().setEnabled(false);
//禁止x轴y轴同时进行缩放
lineChart.setPinchZoom(false);
lineChart.getAxisRight().setEnabled(false);//关闭右侧Y轴
lineChart.setDrawGridBackground(false);
Legend legend = lineChart.getLegend();
legend.setEnabled(false);
//获取x,y轴
yAxis = lineChart.getAxisLeft();
xAxis = lineChart.getXAxis();
//设置x,y轴
xAxis.setEnabled(false);//关闭x轴
//保证Y轴从0开始,不然会上移一点
yAxis.setAxisMinimum(0f);
yAxis.setDrawGridLines(false);
}
/**
* 初始化dataset
* @param name
* @param color
*/
private void initLineDataSet(String name,int color) {
if(entries==null){
entries= new ArrayList<>();
entries.add(new Entry(entries.size(),0));
}
//一个LineDataSet就是一条线
lineDataSet = new LineDataSet(null, name);
lineDataSet.setLineWidth(1.5f);
lineDataSet.setCircleRadius(3f);
lineDataSet.setColor(color);
lineDataSet.setCircleColor(color);
lineDataSet.setHighLightColor(color);
//设置曲线填充
lineDataSet.setDrawFilled(true);//填充底部颜色
lineDataSet.setAxisDependency(YAxis.AxisDependency.LEFT);
lineDataSet.setValueTextSize(10f);
lineDataSet.setMode(LineDataSet.Mode.CUBIC_BEZIER);//CUBIC_BEZIER
LineChartMarkView mv = new LineChartMarkView(context, xAxis.getValueFormatter());
mv.setChartView(lineChart);
lineChart.setMarker(mv);
lineData = new LineData();
lineChart.setData(lineData);
}
/**
* 设置y轴的值
* @param max
* @param min
* @param labelCount
*/
public void setYAxis(float max, float min, int labelCount) {
if (max < min) {
return;
}
yAxis.setAxisMaximum(max);
yAxis.setAxisMinimum(min);
yAxis.setLabelCount(labelCount, false);
}
/**
* 添加数据,只保留10个
* @param number
*/
public void addEntry(Double number) {
//只保留最新的10个,超过时,将第一个移除,其他的向前移动
if(entries.size()>=10){
entries.remove(0);
for (int i=0;i<entries.size();i++){
Entry entry = entries.get(i);
entry.setX(i-1);
entries.set(i,entry);
}
}
//将最新的添加进去,
entries.add(new Entry(entries.size(),number.floatValue()));
lineDataSet.setValues(entries);
//不显示折线上的值
lineDataSet.setDrawValues(false);
lineData=new LineData(lineDataSet);
lineChart.setData(lineData);
lineChart.notifyDataSetChanged();//对图表数据进行更新
lineChart.invalidate();
}
}
Activity中只用于调用
public class DyLineChartActivity extends Activity {
@BindView(R.id.dy_line_chart)
LineChart lineChart;
DyLineChartUtils dy;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.mp_dy_line_chart);
ButterKnife.bind(this);
initView();
getLineChart();
}
private void initView() {
lineChart=(LineChart)findViewById(R.id.chart);
dy=new DyLineChartUtils(lineChart,"体温",Color.CYAN,this,40,0,5);
}
public void getLineChart() {
//死循环查询数据
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
runOnUiThread(new Runnable() {
@Override
public void run() {
double value = (Math.random() * 20) + 15;
dy.addEntry(value);
Log.i("info", "此时value的值为===============>"+value);
}
});
}
}
}).start();
}
}
如果有什么问题欢迎讨论,有什么错误欢迎指出