MpAndroidChart-LineChart 折线图使用(含动态添加点,动态添加曲线)
目录零、简介一、MpAndroidChart的基本使用1.依赖:project的build.gradle 中添加2.app的build.gradle 中添加3.举例4.常用API二、MpAndroidChart-LineChart的基本使用配置1.XAxis(X轴)2.YAxis(Y轴)3.Legend(图例:即上图所示的曲线图下面的 温度)4.Desc...
目录
二、MpAndroidChart-LineChart的基本使用配置
三、LineChart实现动态添加曲线,以及多曲线动态添加数据
4. 设置图标基本属性:setChartBasicAttr()
6.初始化LineDataSet(一条曲线):initLineDataSet()
10. 设置MarkerView: setMarkerView()
零、简介
本文主要介绍MpAndroidChart中的折线图-LineChart的基本使用,包含动态添加点,动态添加线,以及曲线的隐藏与显示等等。
话不多说,先上图:
GitHub地址:https://github.com/PhilJay/MPAndroidChart
文档地址:https://jitpack.io/com/github/PhilJay/MPAndroidChart/v3.0.2/javadoc
一、MpAndroidChart的基本使用
1.依赖:project的build.gradle 中添加
allprojects {
repositories {
jcenter()
maven { url "https://jitpack.io" }
}
}
2.app的build.gradle 中添加
implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0-alpha'
3.举例
3.1 xml中示例
<com.github.mikephil.charting.charts.LineChart
android:id="@+id/mvDetailLineChart"
android:layout_width="match_parent"
android:layout_height="@dimen/dp200"/>
3.2 java代码示例
@Override
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
LineChart mLineChart = (LineChart) findViewById(R.id.lineChart);
//显示边界
mLineChart.setDrawBorders(true);
//设置数据
List<Entry> entries = new ArrayList<>();
for (int i = 0; i < 10; i++) {
entries.add(new Entry(i, (float) (Math.random()) * 80));
} //一个LineDataSet就是一条线
LineDataSet lineDataSet = new LineDataSet(entries, "温度");
LineData data = new LineData(lineDataSet);
mLineChart.setData(data);
}
3.3 效果图:
4.常用API
setDescription(String desc)
: 设置表格的描述setDescriptionTypeface(Typeface t)
:自定义表格中显示的字体setDrawYValues(boolean enabled)
: 设置是否显示y轴的值的数据setValuePaintColor(int color)
:设置表格中y轴的值的颜色,但是必须设置setDrawYValues(true)setValueTypeface(Typeface t):设置字体
setValueFormatter(DecimalFormat format)
: 设置显示的格式setPaint(Paint p, int which)
: 自定义笔刷
public ChartData getDataCurrent()
:返回ChartData对象当前显示的图表。它包含了所有信息的显示值最小和最大值等public float getYChartMin()
: 返回当前最小值public float getYChartMax()
: 返回当前最大值public float getAverage()
: 返回所有值的平均值。public float getAverage(int type)
: 返回平均值public PointF getCenter()
: 返回中间点public Paint getPaint(int which)
: 得到笔刷
setTouchEnabled(boolean enabled)
: 设置是否可以触摸,如为false,则不能拖动,缩放等setDragScaleEnabled(boolean enabled)
: 设置是否可以拖拽,缩放setOnChartValueSelectedListener(OnChartValueSelectedListener l)
: 设置表格上的点,被点击的时候,的回调函数setHighlightEnabled(boolean enabled)
: 设置点击value的时候,是否高亮显示public void highlightValues(Highlight[] highs)
: 设置高亮显示
saveToGallery(String title)
: 保存图表到图库中saveToPath(String title, String pathOnSD)
: 保存.setScaleMinima(float x, float y)
: 设置最小的缩放centerViewPort(int xIndex, float val)
: 设置视口fitScreen()
: 适应屏幕
动画:
所有的图表类型都支持下面三种动画,分别是x方向,y方向,xy方向。
animateX(int durationMillis)
: x轴方向animateY(int durationMillis)
: y轴方向animateXY(int xDuration, int yDuration)
: xy轴方向
二、MpAndroidChart-LineChart的基本使用配置
使用MpAndroidchart前首先要明白几个概念,以免在编码时混淆概念
LineChart // 折线表,存线集合,与xml中的控件绑定实力化
LineData // 线集合,所有折线以数组的形式存到此集合中
LineDataSet // 点集合,即一条折线
Entry // 某条折线上的一个点
XAxis // X轴
YAxis // Y轴,Y轴分左右,通过lineChart的getAxisLeft()、getAxisRight()得到
Legend // 图例,即标识哪一条曲线,如用红色标识电流折线,蓝色标识电压折线
LimitLine // 限制线
Description // 描述
List<Float> list = new ArrayList<>(); // 存放数据的list列表
List<Entry> entrys = new ArrayList<>(); // 存放折线需要的点的列表
LineDataSet mStepTimeDataSet = new LineDataSet(entrys, "步时间"); // LineDataSet:点集合,即一条线
图解
1.XAxis(X轴)
设置x轴需要注意一下几个点:
- 设置x轴的坐标之间的最小间隔,如xAxis.setGranularity(1f),即间隔为1、
- 设置x轴的最大/小值,xAxis.setAxisMinimum(0f),xAxis.setAxisMaximum(20f),则x轴的范围是0-20
- 设置x轴的刻度数量,xAxis.setLabelCount(10, true),即x轴有10个刻度线,此时一个刻度表示2,如果是将10改为40,由于之前设置了坐标之间的间隔,所以x轴一个刻度会表示1,而不是0.5.
- 设置当前页面显示几个刻度,mLineChart.setVisibleXRangeMaximum(6),// 设置当前图表中最多在x轴坐标线上显示的刻度线总量为6
1.得到X轴:
XAxis xAxis = mLineChart.getXAxis();
2.设置X轴的位置(默认在上方):
xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);//值:BOTTOM,BOTH_SIDED,BOTTOM_INSIDE,TOP,TOP_INSIDE
3.设置X轴坐标之间的最小间隔(因为此图有缩放功能,X轴,Y轴可设置可缩放)
xAxis.setGranularity(1f);
4.设置X轴的刻度数量
xAxis.setLabelCount(12, true);
5.设置X轴的值(最小值、最大值、然后会根据设置的刻度数量自动分配刻度显示)
xAxis.setAxisMinimum(0f);
xAxis.setAxisMaximum(20f);
6.设置当前图表中最多在x轴坐标线上显示刻度线的总量
mLineChart.setVisibleXRangeMaximum(6);// 设置当前图表中最多在x轴坐标线上显示的刻度线总量为6
7.设置X轴值为字符串(如上右图)
xAxis.setValueFormatter(new IAxisValueFormatter() {
@Override
public String getFormattedValue(float value, AxisBase axis) {
return mList.get((int) value); //mList为存有月份的String集合
}
});
想要显示完整的12个月份,要与(x,y)坐标对应数量应该为12
for (int i = 0; i < 12; i++) {
entries.add(new Entry(i, (float) (Math.random()) * 80)); //Entry(float x, float y)
}
还有设置线条颜色、字体颜色、等等,可查看详细的文档。
8.取消曲线显示的值为整数
与设置自定义X轴类似,设置曲线显示值为整数,可在设置曲线LineDataSet 时,修改值的类型
lineDataSet.setValueFormatter(new IValueFormatter() {
@Override
public String getFormattedValue(float value, Entry entry, int dataSetIndex, ViewPortHandler viewPortHandler) {
int IValue = (int) value;
return String.valueOf(IValue);
}
});
2.YAxis(Y轴)
Y轴和X轴类似,不过Y轴分左右,这里只介绍几个不同的地方
1.得到Y轴
YAxis leftYAxis = mLineChart.getAxisLeft();
YAxis rightYAxis = mLineChart.getAxisRight();
2.设置某一个Y轴是否显示
rightYAxis.setEnabled(false); //右侧Y轴不显示
3.限制线LimitLine(如上右图)
LimitLine limitLine = new LimitLine(95,"高限制性"); //得到限制线
limitLine.setLineWidth(4f); //宽度
limitLine.setTextSize(10f);
limitLine.setTextColor(Color.RED); //颜色
limitLine.setLineColor(Color.BLUE);
rightYAxis.addLimitLine(limitLine); //Y轴添加限制线
4.X轴和Y轴类似,都具有相同的属性方法
rightYAxis.setAxisMinimum(0f);
rightYAxis.setAxisMaximum(100f);
rightYAxis.setGranularity(1f);
rightYAxis.setLabelCount(11,false);
rightYAxis.setTextColor(Color.BLUE); //文字颜色
rightYAxis.setGridColor(Color.RED); //网格线颜色
rightYAxis.setAxisLineColor(Color.GREEN); //Y轴颜色
以及格式化Y轴的值
leftYAxis.setValueFormatter(new IAxisValueFormatter() {
@Override
public String getFormattedValue(float value, AxisBase axis) {
return (int) value + "%";
}
});
3.Legend(图例:即上图所示的曲线图下面的 温度)
1.得到Lengend
Legend legend = mLineChart.getLegend();
2.设置Lengend位置
legend.setTextColor(Color.CYAN); //设置Legend 文本颜色
legend.setVerticalAlignment(Legend.LegendVerticalAlignment.BOTTOM);
legend.setHorizontalAlignment(Legend.LegendHorizontalAlignment.CENTER);
legend.setOrientation(Legend.LegendOrientation.HORIZONTAL);
3.设置标签是否换行(当多条标签时 需要换行显示、如上右图)
true:可换行。false:不换行
legend.setWordWrapEnabled(true);
4.隐藏Lengend
legend.setEnabled(false);
4.Description(描述)
1.隐藏描述
Description description = new Description();
description.setEnabled(false);
mLineChart.setDescription(description);
2.设置描述内容
Description description = new Description();
description.setText("X轴描述");
description.setTextColor(Color.RED);
mLineChart.setDescription(description);
5.MarkerView
MarkerView可自定义,用于点击图标值时显示想要的内容
1.自定义MarkerView
public class MyMarkerView extends MarkerView {
private TextView tvContent;
private DecimalFormat format = new DecimalFormat("##0");
public MyMarkerView(Context context) {
super(context, R.layout.layout_markerview);
tvContent = (TextView) findViewById(R.id.tvContent);
}
@Override
public void refreshContent(Entry e, Highlight highlight) {
tvContent.setText(format.format(e.getY()));
super.refreshContent(e, highlight);
}
@Override
public MPPointF getOffset() {
return new MPPointF(-(getWidth() / 2), -getHeight() - 10);
}
}
2.设置显示MarkerView
MyMarkerView mv = new MyMarkerView(this);
mLineChart.setMarkerView(mv);
6.折线图的线条设置
LineDataSet lineDataSet = new LineDataSet(entries, "温度");//一个LineDataSet就是一条线
lineDataSet.setDrawCircleHole(false);//设置曲线值的圆点是实心还是空心
lineDataSet.setValueTextSize(9f);//设置显示值的字体大小
lineDataSet.setMode(LineDataSet.Mode.CUBIC_BEZIER);//线模式为圆滑曲线(默认折线)
三、LineChart实现动态添加曲线,以及多曲线动态添加数据
接下来我们实现一个LineChart图表,它包含动态添加曲线,以及多曲线动态添加数据,
下面是代码逻辑:
- 默认添加三条折线,但是这三条曲线中暂时不添加点,后面我们动态添加
- 有个Handler用于发从动态添加点的消息,延时一秒发一次
- 有两个Button,一个控制开始添加点,一个控制暂停添加点
- 还有三个CheckBox,对应三条折线,那个选中便显示哪条曲线
效果图:
1. 在xml中添加基本控件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".module.details.LineChartDemo">
<com.github.mikephil.charting.charts.LineChart
android:id="@+id/demo_linechart"
android:layout_width="match_parent"
android:layout_height="@dimen/dp200" />
<CheckBox
android:id="@+id/demo_checkbox1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:checked="true"
android:text="折线1" />
<CheckBox
android:id="@+id/demo_checkbox2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="折线2" />
<CheckBox
android:id="@+id/demo_checkbox3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="折线3" />
<Button
android:id="@+id/demo_start"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="开始"/>
<Button
android:id="@+id/demo_pause"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="暂停"/>
</LinearLayout>
2.初始化基本属性,控件
首先声明了Handler所需要的消息,折线编号,基本控件,以及LineChart所需要的对象。
之后 封装了Activity的启动方式,以及随机产生Y值的方法。
然后在onCreate方法中对控件初始化
public class LineChartDemo extends AppCompatActivity implements View.OnClickListener {
public static final int MSG_START = 1; // handler消息,开始添加点
// 折线编号
public static final int LINE_NUMBER_1 = 0;
public static final int LINE_NUMBER_2 = 1;
public static final int LINE_NUMBER_3 = 2;
/**
* 功能:启动方式
*/
public static void startActivity(Context context) {
context.startActivity(new Intent(context, LineChartDemo.class));
}
private DemoHandler mDemoHandler; // 自定义Handler
private Random mRandom = new Random(); // 随机产生点
private DecimalFormat mDecimalFormat = new DecimalFormat("#.00"); // 格式化浮点数位两位小数
Button mBtnStart; // 开始添加点
Button mBtnPause; // 暂停添加点
CheckBox mCheckBox1;
CheckBox mCheckBox2;
CheckBox mCheckBox3;
List<CheckBox> mCheckBoxList = new ArrayList<>();
LineChart mLineChart; // 折线表,存线集合
LineData mLineData; // 线集合,所有折现以数组的形式存到此集合中
XAxis mXAxis; //X轴
YAxis mLeftYAxis; //左侧Y轴
YAxis mRightYAxis; //右侧Y轴
Legend mLegend; //图例
LimitLine mLimitline; //限制线
// Y值数据链表
List<Float> mList1 = new ArrayList<>();
List<Float> mList2 = new ArrayList<>();
List<Float> mList3 = new ArrayList<>();
// Chart需要的点数据链表
List<Entry> mEntries1 = new ArrayList<>();
List<Entry> mEntries2 = new ArrayList<>();
List<Entry> mEntries3 = new ArrayList<>();
// LineDataSet:点集合,即一条线
LineDataSet mLineDataSet1 = new LineDataSet(mEntries1, "折线1");
LineDataSet mLineDataSet2 = new LineDataSet(mEntries2, "折线2");
LineDataSet mLineDataSet3 = new LineDataSet(mEntries3, "折线3");
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.demo_activity_line_chart);
mDemoHandler = new DemoHandler(this);
initView();
}
/**
* 功能:产生随机数(小数点两位)
*/
public Float getRandom(Float seed) {
return Float.valueOf(mDecimalFormat.format(mRandom.nextFloat() * seed));
}
/**
* 功能:初始化基本控件,button,checkbox
*/
public void initView() {
mBtnStart = findViewById(R.id.demo_start);
mBtnPause = findViewById(R.id.demo_pause);
mCheckBox1 = findViewById(R.id.demo_checkbox1);
mCheckBox2 = findViewById(R.id.demo_checkbox2);
mCheckBox3 = findViewById(R.id.demo_checkbox3);
mCheckBoxList.add(mCheckBox1);
mCheckBoxList.add(mCheckBox2);
mCheckBoxList.add(mCheckBox3);
mBtnStart.setOnClickListener(this);
mBtnPause.setOnClickListener(this);
mCheckBox1.setOnClickListener(this);
mCheckBox2.setOnClickListener(this);
mCheckBox3.setOnClickListener(this);
}
}
3. 初始化折线:initLineChart()
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.demo_activity_line_chart);
mDemoHandler = new DemoHandler(this);
initView(); // 初始化控件
initLineChart(); // 初始化折线图
}
initLineChart()方法:
/**
* 功能:初始化LineChart
*/
public void initLineChart() {
mLineChart = findViewById(R.id.demo_linechart);
mXAxis = mLineChart.getXAxis(); // 得到x轴
mLeftYAxis = mLineChart.getAxisLeft(); // 得到侧Y轴
mRightYAxis = mLineChart.getAxisRight(); // 得到右侧Y轴
mLegend = mLineChart.getLegend(); // 得到图例
mLineData = new LineData();
mLineChart.setData(mLineData);
// 设置图标基本属性
setChartBasicAttr(mLineChart);
// 设置XY轴
setXYAxis(mLineChart, mXAxis, mLeftYAxis, mRightYAxis);
// 添加线条
initLine();
// 设置图例
createLegend(mLegend);
// 设置MarkerView
setMarkerView(mLineChart);
}
4. 设置图标基本属性:setChartBasicAttr()
/**
* 功能:设置图标的基本属性
*/
void setChartBasicAttr(LineChart lineChart) {
/***图表设置***/
lineChart.setDrawGridBackground(false); //是否展示网格线
lineChart.setDrawBorders(true); //是否显示边界
lineChart.setDragEnabled(true); //是否可以拖动
lineChart.setScaleEnabled(true); // 是否可以缩放
lineChart.setTouchEnabled(true); //是否有触摸事件
//设置XY轴动画效果
//lineChart.animateY(2500);
lineChart.animateX(1500);
}
5. 设置XY轴:setXYAxis()
/**
* 功能:设置XY轴
*/
void setXYAxis(LineChart lineChart, XAxis xAxis, YAxis leftYAxis, YAxis rightYAxis) {
/***XY轴的设置***/
xAxis.setPosition(XAxis.XAxisPosition.BOTTOM); //X轴设置显示位置在底部
xAxis.setAxisMinimum(0f); // 设置X轴的最小值
xAxis.setAxisMaximum(20); // 设置X轴的最大值
xAxis.setLabelCount(20, false); // 设置X轴的刻度数量,第二个参数表示是否平均分配
xAxis.setGranularity(1f); // 设置X轴坐标之间的最小间隔
lineChart.setVisibleXRangeMaximum(5);// 当前统计图表中最多在x轴坐标线上显示的总量
//保证Y轴从0开始,不然会上移一点
leftYAxis.setAxisMinimum(0f);
rightYAxis.setAxisMinimum(0f);
leftYAxis.setAxisMaximum(100f);
rightYAxis.setAxisMaximum(100f);
leftYAxis.setGranularity(1f);
rightYAxis.setGranularity(1f);
leftYAxis.setLabelCount(20);
lineChart.setVisibleYRangeMaximum(30, YAxis.AxisDependency.LEFT);// 当前统计图表中最多在Y轴坐标线上显示的总量
lineChart.setVisibleYRangeMaximum(30, YAxis.AxisDependency.RIGHT);// 当前统计图表中最多在Y轴坐标线上显示的总量
leftYAxis.setEnabled(false);
// leftYAxis.setCenterAxisLabels(true);// 将轴标记居中
// leftYAxis.setDrawZeroLine(true); // 原点处绘制 一条线
// leftYAxis.setZeroLineColor(Color.RED);
// leftYAxis.setZeroLineWidth(1f);
}
6.初始化LineDataSet(一条曲线):initLineDataSet()
此方法被在创建一个线条时调用,为曲线初始化做好准备
/**
* 曲线初始化设置,一个LineDataSet 代表一条曲线
*
* @param lineDataSet 线条
* @param color 线条颜色
* @param mode
*/
private void initLineDataSet(LineDataSet lineDataSet, int color, LineDataSet.Mode mode) {
lineDataSet.setColor(color); // 设置曲线颜色
lineDataSet.setCircleColor(color); // 设置数据点圆形的颜色
lineDataSet.setDrawCircleHole(false);// 设置曲线值的圆点是否是空心
lineDataSet.setLineWidth(1f); // 设置折线宽度
lineDataSet.setCircleRadius(3f); // 设置折现点圆点半径
lineDataSet.setValueTextSize(10f);
lineDataSet.setDrawFilled(true); //设置折线图填充
lineDataSet.setFormLineWidth(1f);
lineDataSet.setFormSize(15.f);
if (mode == null) {
//设置曲线展示为圆滑曲线(如果不设置则默认折线)
lineDataSet.setMode(LineDataSet.Mode.CUBIC_BEZIER);
} else {
lineDataSet.setMode(mode);
}
}
7.动态创建并添加一个线条:createLine()
根据传进来的dataList,生成点Entry,之后根据生成的点更新折线图即可
/**
* 功能:动态创建一条曲线
*/
private void createLine(List<Float> dataList, List<Entry> entries, LineDataSet lineDataSet, int color, LineData lineData, LineChart lineChart) {
for (int i = 0; i < dataList.size(); i++) {
/**
* 在此可查看 Entry构造方法,可发现 可传入数值 Entry(float x, float y)
* 也可传入Drawable, Entry(float x, float y, Drawable icon) 可在XY轴交点 设置Drawable图像展示
*/
Entry entry = new Entry(i, dataList.get(i));// Entry(x,y)
entries.add(entry);
}
// 初始化线条
initLineDataSet(lineDataSet, color, LineDataSet.Mode.CUBIC_BEZIER);
if (lineData == null) {
lineData = new LineData();
lineData.addDataSet(lineDataSet);
lineChart.setData(lineData);
} else {
lineChart.getLineData().addDataSet(lineDataSet);
}
lineChart.invalidate();
}
8. 初始化项目中的三条折线:initLine()
首先创建三条折线,之后设置三条折线隐藏,最后根据配置默认显示第一条折线
/**
* 功能:对图表中的曲线初始化,添加三条,并且默认显示第一条
*/
void initLine() {
createLine(mList1, mEntries1, mLineDataSet1, LColor.Colors.RED.getColor(), mLineData, mLineChart);
createLine(mList2, mEntries2, mLineDataSet2, LColor.Colors.ORANGE.getColor(), mLineData, mLineChart);
createLine(mList3, mEntries3, mLineDataSet3, LColor.Colors.YELLOW.getColor(), mLineData, mLineChart);
// mLineData.getDataSetCount() 总线条数
// mLineData.getEntryCount() 总点数
// mLineData.getDataSetByIndex(index).getEntryCount() 索引index处折线的总点数
// 每条曲线添加到mLineData后,从索引0处开始排列
for (int i = 0; i < mLineData.getDataSetCount(); i++) {
mLineChart.getLineData().getDataSets().get(i).setVisible(false); //
}
showLine(LINE_NUMBER_1);
}
9. 设置图例:createLegend()
/**
* 功能:创建图例
*/
private void createLegend(Legend legend) {
/***折线图例 标签 设置***/
//设置显示类型,LINE CIRCLE SQUARE EMPTY 等等 多种方式,查看LegendForm 即可
legend.setForm(Legend.LegendForm.CIRCLE);
legend.setTextSize(12f);
//显示位置 左下方
legend.setVerticalAlignment(Legend.LegendVerticalAlignment.BOTTOM);
legend.setHorizontalAlignment(Legend.LegendHorizontalAlignment.LEFT);
legend.setOrientation(Legend.LegendOrientation.HORIZONTAL);
//是否绘制在图表里面
legend.setDrawInside(false);
legend.setEnabled(true);
}
10. 设置MarkerView: setMarkerView()
/**
* 设置 可以显示X Y 轴自定义值的 MarkerView
*/
public void setMarkerView(LineChart lineChart) {
LineChartMarkViewDemo mv = new LineChartMarkViewDemo(this);
mv.setChartView(lineChart);
lineChart.setMarker(mv);
lineChart.invalidate();
}
LineChartMarkViewDemo是自定义的,这个很简单,一般是自定义XML,之后继承MarkView即可。
xml:
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:background="@drawable/shape_square"
android:orientation="vertical">
<TextView
android:id="@+id/xValues_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@android:color/white"
tools:text="123" />
<TextView
android:id="@+id/yValue_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:textColor="@android:color/white"
tools:text="222123" />
</LinearLayout>
java
public class LineChartMarkViewDemo extends MarkerView {
DecimalFormat df = new DecimalFormat(".00");
private TextView mXValueTv;
private TextView mYValueTv;
public LineChartMarkViewDemo(Context context) {
super(context, R.layout.layout_markview);
mXValueTv = findViewById(R.id.xValues_tv);
mYValueTv = findViewById(R.id.yValue_tv);
}
@SuppressLint("SetTextI18n")
@Override
public void refreshContent(Entry e, Highlight highlight) {
//展示自定义X轴值 后的X轴内容
mXValueTv.setText("X = " + df.format(e.getX()));
mYValueTv.setText("Y = " + df.format(e.getY()));
super.refreshContent(e, highlight);
}
@Override
public MPPointF getOffset() {
return new MPPointF(-(getWidth() / 2), -getHeight());
}
}
11.动态添加数据点:addEntry()
/**
* 动态添加数据
* 在一个LineChart中存放的折线,其实是以索引从0开始编号的
*
* @param yValues y值
*/
public void addEntry(LineData lineData, LineChart lineChart, float yValues, int index) {
// 通过索引得到一条折线,之后得到折线上当前点的数量
int xCount = lineData.getDataSetByIndex(index).getEntryCount();
Entry entry = new Entry(xCount, yValues); // 创建一个点
lineData.addEntry(entry, index); // 将entry添加到指定索引处的折线中
//通知数据已经改变
lineData.notifyDataChanged();
lineChart.notifyDataSetChanged();
//把yValues移到指定索引的位置
lineChart.moveViewToAnimated(xCount - 4, yValues, YAxis.AxisDependency.LEFT, 1000);// TODO: 2019/5/4 内存泄漏,异步 待修复
lineChart.invalidate();
}
/**
* 功能:第1条折线添加一个点
*/
public void addLine1Data(float yValues) {
addEntry(mLineData, mLineChart, yValues, LINE_NUMBER_1);
}
/**
* 功能:第2条折线添加一个点
*/
public void addLine2Data(float yValues) {
addEntry(mLineData, mLineChart, yValues, LINE_NUMBER_2);
}
/**
* 功能:第3条折线添加一个点
*/
public void addLine3Data(float yValues) {
addEntry(mLineData, mLineChart, yValues, LINE_NUMBER_3);
}
12.自定义Handler:DemoHandler
自定义一个Handler,通过静态内部类+弱引用的方式可以很好的防止内存泄漏
封装发送和暂停方法:
/**
* 功能:发送开始
*/
void sendStartAddEntry() {
if (!mDemoHandler.hasMessages(MSG_START)) { // 判断是否有消息队列此消息,如果没有则发送
mDemoHandler.sendEmptyMessageDelayed(MSG_START, 1000);
}
}
/**
* 功能:暂停添加点,即移除所有消息
*/
void sendPauseAddEntry() {
mDemoHandler.removeCallbacksAndMessages(null);
}
自定义Handler
/**
* 功能:自定义Handler,通过弱引用的方式防止内存泄漏
*/
private static class DemoHandler extends Handler {
WeakReference<LineChartDemo> mReference;
DemoHandler(LineChartDemo activity) {
mReference = new WeakReference<>(activity);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
LineChartDemo lineChartDemo = mReference.get();
if (lineChartDemo == null) {
return;
}
switch (msg.what) {
case MSG_START:
lineChartDemo.addLine1Data(lineChartDemo.getRandom(30f));
lineChartDemo.addLine2Data(lineChartDemo.getRandom(20f));
lineChartDemo.addLine3Data(lineChartDemo.getRandom(10f));
lineChartDemo.sendStartAddEntry();
break;
default:
}
}
}
13. 点击事件:onClick()
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.demo_start:
sendStartAddEntry();
break;
case R.id.demo_pause:
sendPauseAddEntry();
break;
case R.id.demo_checkbox1:
showLine(LINE_NUMBER_1);
break;
case R.id.demo_checkbox2:
showLine(LINE_NUMBER_2);
break;
case R.id.demo_checkbox3:
showLine(LINE_NUMBER_3);
break;
default:
}
}
14.最后一步,回收:onDestory
@Override
protected void onDestroy() {
super.onDestroy();
// 清空消息
mDemoHandler.removeCallbacksAndMessages(null);
mDemoHandler = null;
// moveViewToAnimated 移动到某个点,有内存泄漏,暂未修复,希望网友可以指着
mLineChart.clearAllViewportJobs();
mLineChart.removeAllViewsInLayout();
mLineChart.removeAllViews();
}
四、全部Java代码
XML,以及自定义MarkView已经在上面给出了,现在补上全部的java代码
package com.liang.batterytestsystem.module.details;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import com.github.mikephil.charting.charts.LineChart;
import com.github.mikephil.charting.components.Legend;
import com.github.mikephil.charting.components.LimitLine;
import com.github.mikephil.charting.components.XAxis;
import com.github.mikephil.charting.components.YAxis;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.data.LineData;
import com.github.mikephil.charting.data.LineDataSet;
import com.liang.batterytestsystem.R;
import com.liang.batterytestsystem.utils.LColor;
import com.liang.liangutils.utils.LLogX;
import com.liang.liangutils.view.LTitleView;
import java.lang.ref.WeakReference;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class LineChartDemo extends AppCompatActivity implements View.OnClickListener {
public static final int MSG_START = 1; // handler消息,开始添加点
// 折线编号
public static final int LINE_NUMBER_1 = 0;
public static final int LINE_NUMBER_2 = 1;
public static final int LINE_NUMBER_3 = 2;
/**
* 功能:启动方式
*/
public static void startActivity(Context context) {
context.startActivity(new Intent(context, LineChartDemo.class));
}
private DemoHandler mDemoHandler; // 自定义Handler
private Random mRandom = new Random(); // 随机产生点
private DecimalFormat mDecimalFormat = new DecimalFormat("#.00"); // 格式化浮点数位两位小数
Button mBtnStart; // 开始添加点
Button mBtnPause; // 暂停添加点
CheckBox mCheckBox1;
CheckBox mCheckBox2;
CheckBox mCheckBox3;
List<CheckBox> mCheckBoxList = new ArrayList<>();
LineChart mLineChart; // 折线表,存线集合
LineData mLineData; // 线集合,所有折现以数组的形式存到此集合中
XAxis mXAxis; //X轴
YAxis mLeftYAxis; //左侧Y轴
YAxis mRightYAxis; //右侧Y轴
Legend mLegend; //图例
LimitLine mLimitline; //限制线
// Y值数据链表
List<Float> mList1 = new ArrayList<>();
List<Float> mList2 = new ArrayList<>();
List<Float> mList3 = new ArrayList<>();
// Chart需要的点数据链表
List<Entry> mEntries1 = new ArrayList<>();
List<Entry> mEntries2 = new ArrayList<>();
List<Entry> mEntries3 = new ArrayList<>();
// LineDataSet:点集合,即一条线
LineDataSet mLineDataSet1 = new LineDataSet(mEntries1, "折线1");
LineDataSet mLineDataSet2 = new LineDataSet(mEntries2, "折线2");
LineDataSet mLineDataSet3 = new LineDataSet(mEntries3, "折线3");
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.demo_activity_line_chart);
mDemoHandler = new DemoHandler(this);
initView();
initLineChart();
}
/**
* 功能:产生随机数(小数点两位)
*/
public Float getRandom(Float seed) {
return Float.valueOf(mDecimalFormat.format(mRandom.nextFloat() * seed));
}
/**
* 功能:初始化基本控件,button,checkbox
*/
public void initView() {
mBtnStart = findViewById(R.id.demo_start);
mBtnPause = findViewById(R.id.demo_pause);
mCheckBox1 = findViewById(R.id.demo_checkbox1);
mCheckBox2 = findViewById(R.id.demo_checkbox2);
mCheckBox3 = findViewById(R.id.demo_checkbox3);
mCheckBoxList.add(mCheckBox1);
mCheckBoxList.add(mCheckBox2);
mCheckBoxList.add(mCheckBox3);
mBtnStart.setOnClickListener(this);
mBtnPause.setOnClickListener(this);
mCheckBox1.setOnClickListener(this);
mCheckBox2.setOnClickListener(this);
mCheckBox3.setOnClickListener(this);
}
/**
* 功能:初始化LineChart
*/
public void initLineChart() {
mLineChart = findViewById(R.id.demo_linechart);
mXAxis = mLineChart.getXAxis(); // 得到x轴
mLeftYAxis = mLineChart.getAxisLeft(); // 得到侧Y轴
mRightYAxis = mLineChart.getAxisRight(); // 得到右侧Y轴
mLegend = mLineChart.getLegend(); // 得到图例
mLineData = new LineData();
mLineChart.setData(mLineData);
// 设置图标基本属性
setChartBasicAttr(mLineChart);
// 设置XY轴
setXYAxis(mLineChart, mXAxis, mLeftYAxis, mRightYAxis);
// 添加线条
initLine();
// 设置图例
createLegend(mLegend);
// 设置MarkerView
setMarkerView(mLineChart);
}
/**
* 功能:设置图标的基本属性
*/
void setChartBasicAttr(LineChart lineChart) {
/***图表设置***/
lineChart.setDrawGridBackground(false); //是否展示网格线
lineChart.setDrawBorders(true); //是否显示边界
lineChart.setDragEnabled(true); //是否可以拖动
lineChart.setScaleEnabled(true); // 是否可以缩放
lineChart.setTouchEnabled(true); //是否有触摸事件
//设置XY轴动画效果
//lineChart.animateY(2500);
lineChart.animateX(1500);
}
/**
* 功能:设置XY轴
*/
void setXYAxis(LineChart lineChart, XAxis xAxis, YAxis leftYAxis, YAxis rightYAxis) {
/***XY轴的设置***/
xAxis.setPosition(XAxis.XAxisPosition.BOTTOM); //X轴设置显示位置在底部
xAxis.setAxisMinimum(0f); // 设置X轴的最小值
xAxis.setAxisMaximum(20); // 设置X轴的最大值
xAxis.setLabelCount(20, false); // 设置X轴的刻度数量,第二个参数表示是否平均分配
xAxis.setGranularity(1f); // 设置X轴坐标之间的最小间隔
lineChart.setVisibleXRangeMaximum(5);// 当前统计图表中最多在x轴坐标线上显示的总量
//保证Y轴从0开始,不然会上移一点
leftYAxis.setAxisMinimum(0f);
rightYAxis.setAxisMinimum(0f);
leftYAxis.setAxisMaximum(100f);
rightYAxis.setAxisMaximum(100f);
leftYAxis.setGranularity(1f);
rightYAxis.setGranularity(1f);
leftYAxis.setLabelCount(20);
lineChart.setVisibleYRangeMaximum(30, YAxis.AxisDependency.LEFT);// 当前统计图表中最多在Y轴坐标线上显示的总量
lineChart.setVisibleYRangeMaximum(30, YAxis.AxisDependency.RIGHT);// 当前统计图表中最多在Y轴坐标线上显示的总量
leftYAxis.setEnabled(false);
// leftYAxis.setCenterAxisLabels(true);// 将轴标记居中
// leftYAxis.setDrawZeroLine(true); // 原点处绘制 一条线
// leftYAxis.setZeroLineColor(Color.RED);
// leftYAxis.setZeroLineWidth(1f);
}
/**
* 功能:对图表中的曲线初始化,添加三条,并且默认显示第一条
*/
void initLine() {
createLine(mList1, mEntries1, mLineDataSet1, LColor.Colors.RED.getColor(), mLineData, mLineChart);
createLine(mList2, mEntries2, mLineDataSet2, LColor.Colors.ORANGE.getColor(), mLineData, mLineChart);
createLine(mList3, mEntries3, mLineDataSet3, LColor.Colors.YELLOW.getColor(), mLineData, mLineChart);
// mLineData.getDataSetCount() 总线条数
// mLineData.getEntryCount() 总点数
// mLineData.getDataSetByIndex(index).getEntryCount() 索引index处折线的总点数
// 每条曲线添加到mLineData后,从索引0处开始排列
for (int i = 0; i < mLineData.getDataSetCount(); i++) {
mLineChart.getLineData().getDataSets().get(i).setVisible(false); //
}
showLine(LINE_NUMBER_1);
}
/**
* 功能:根据索引显示或隐藏指定线条
*/
public void showLine(int index) {
mLineChart
.getLineData()
.getDataSets()
.get(index)
.setVisible(mCheckBoxList.get(index).isChecked());
mLineChart.invalidate();
}
/**
* 功能:动态创建一条曲线
*/
private void createLine(List<Float> dataList, List<Entry> entries, LineDataSet lineDataSet, int color, LineData lineData, LineChart lineChart) {
for (int i = 0; i < dataList.size(); i++) {
/**
* 在此可查看 Entry构造方法,可发现 可传入数值 Entry(float x, float y)
* 也可传入Drawable, Entry(float x, float y, Drawable icon) 可在XY轴交点 设置Drawable图像展示
*/
Entry entry = new Entry(i, dataList.get(i));// Entry(x,y)
entries.add(entry);
}
// 初始化线条
initLineDataSet(lineDataSet, color, LineDataSet.Mode.CUBIC_BEZIER);
if (lineData == null) {
lineData = new LineData();
lineData.addDataSet(lineDataSet);
lineChart.setData(lineData);
} else {
lineChart.getLineData().addDataSet(lineDataSet);
}
lineChart.invalidate();
}
/**
* 曲线初始化设置,一个LineDataSet 代表一条曲线
*
* @param lineDataSet 线条
* @param color 线条颜色
* @param mode
*/
private void initLineDataSet(LineDataSet lineDataSet, int color, LineDataSet.Mode mode) {
lineDataSet.setColor(color); // 设置曲线颜色
lineDataSet.setCircleColor(color); // 设置数据点圆形的颜色
lineDataSet.setDrawCircleHole(false);// 设置曲线值的圆点是否是空心
lineDataSet.setLineWidth(1f); // 设置折线宽度
lineDataSet.setCircleRadius(3f); // 设置折现点圆点半径
lineDataSet.setValueTextSize(10f);
lineDataSet.setDrawFilled(true); //设置折线图填充
lineDataSet.setFormLineWidth(1f);
lineDataSet.setFormSize(15.f);
if (mode == null) {
//设置曲线展示为圆滑曲线(如果不设置则默认折线)
lineDataSet.setMode(LineDataSet.Mode.CUBIC_BEZIER);
} else {
lineDataSet.setMode(mode);
}
}
/**
* 功能:创建图例
*/
private void createLegend(Legend legend) {
/***折线图例 标签 设置***/
//设置显示类型,LINE CIRCLE SQUARE EMPTY 等等 多种方式,查看LegendForm 即可
legend.setForm(Legend.LegendForm.CIRCLE);
legend.setTextSize(12f);
//显示位置 左下方
legend.setVerticalAlignment(Legend.LegendVerticalAlignment.BOTTOM);
legend.setHorizontalAlignment(Legend.LegendHorizontalAlignment.LEFT);
legend.setOrientation(Legend.LegendOrientation.HORIZONTAL);
//是否绘制在图表里面
legend.setDrawInside(false);
legend.setEnabled(true);
}
/**
* 设置 可以显示X Y 轴自定义值的 MarkerView
*/
public void setMarkerView(LineChart lineChart) {
LineChartMarkViewDemo mv = new LineChartMarkViewDemo(this);
mv.setChartView(lineChart);
lineChart.setMarker(mv);
lineChart.invalidate();
}
/**
* 动态添加数据
* 在一个LineChart中存放的折线,其实是以索引从0开始编号的
*
* @param yValues y值
*/
public void addEntry(LineData lineData, LineChart lineChart, float yValues, int index) {
// 通过索引得到一条折线,之后得到折线上当前点的数量
int xCount = lineData.getDataSetByIndex(index).getEntryCount();
Entry entry = new Entry(xCount, yValues); // 创建一个点
lineData.addEntry(entry, index); // 将entry添加到指定索引处的折线中
//通知数据已经改变
lineData.notifyDataChanged();
lineChart.notifyDataSetChanged();
//把yValues移到指定索引的位置
lineChart.moveViewToAnimated(xCount - 4, yValues, YAxis.AxisDependency.LEFT, 1000);// TODO: 2019/5/4 内存泄漏,异步 待修复
lineChart.invalidate();
}
/**
* 功能:第1条折线添加一个点
*/
public void addLine1Data(float yValues) {
addEntry(mLineData, mLineChart, yValues, LINE_NUMBER_1);
}
/**
* 功能:第2条折线添加一个点
*/
public void addLine2Data(float yValues) {
addEntry(mLineData, mLineChart, yValues, LINE_NUMBER_2);
}
/**
* 功能:第3条折线添加一个点
*/
public void addLine3Data(float yValues) {
addEntry(mLineData, mLineChart, yValues, LINE_NUMBER_3);
}
/**
* 功能:发送开始
*/
void sendStartAddEntry() {
if (!mDemoHandler.hasMessages(MSG_START)) { // 判断是否有消息队列此消息,如果没有则发送
mDemoHandler.sendEmptyMessageDelayed(MSG_START, 1000);
}
}
/**
* 功能:暂停添加点,即移除所有消息
*/
void sendPauseAddEntry() {
mDemoHandler.removeCallbacksAndMessages(null);
}
@Override
protected void onDestroy() {
super.onDestroy();
// 清空消息
mDemoHandler.removeCallbacksAndMessages(null);
mDemoHandler = null;
// moveViewToAnimated 移动到某个点,有内存泄漏,暂未修复,希望网友可以指着
mLineChart.clearAllViewportJobs();
mLineChart.removeAllViewsInLayout();
mLineChart.removeAllViews();
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.demo_start:
sendStartAddEntry();
break;
case R.id.demo_pause:
sendPauseAddEntry();
break;
case R.id.demo_checkbox1:
showLine(LINE_NUMBER_1);
break;
case R.id.demo_checkbox2:
showLine(LINE_NUMBER_2);
break;
case R.id.demo_checkbox3:
showLine(LINE_NUMBER_3);
break;
default:
}
}
/**
* 功能:自定义Handler,通过弱引用的方式防止内存泄漏
*/
private static class DemoHandler extends Handler {
WeakReference<LineChartDemo> mReference;
DemoHandler(LineChartDemo activity) {
mReference = new WeakReference<>(activity);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
LineChartDemo lineChartDemo = mReference.get();
if (lineChartDemo == null) {
return;
}
switch (msg.what) {
case MSG_START:
lineChartDemo.addLine1Data(lineChartDemo.getRandom(30f));
lineChartDemo.addLine2Data(lineChartDemo.getRandom(20f));
lineChartDemo.addLine3Data(lineChartDemo.getRandom(10f));
lineChartDemo.sendStartAddEntry();
break;
default:
}
}
}
}
参考:
MPAndroidChart折线图(LineChart)的使用,可以左右滑动
Android统计图表MPAndroidChart:动态添加数据更新【6】
更多推荐
所有评论(0)