目錄
二、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】