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.Description(描述)

5.MarkerView

6.折線圖的線條設置

三、LineChart實現動態添加曲線,以及多曲線動態添加數據

1. 在xml中添加基本控件

2.初始化基本屬性,控件

3. 初始化折線:initLineChart()

4. 設置圖標基本屬性:setChartBasicAttr()

5. 設置XY軸:setXYAxis()

6.初始化LineDataSet(一條曲線):initLineDataSet()

7.動態創建並添加一個線條:createLine()

8. 初始化項目中的三條折線:initLine()

9. 設置圖例:createLegend()

10. 設置MarkerView: setMarkerView()

11.動態添加數據點:addEntry()

12.自定義Handler:DemoHandler

13. 點擊事件:onClick()

14.最後一步,回收:onDestory

四、全部Java代碼


零、簡介

本文主要介紹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折線圖詳細使用

MPAndroidChart詳解

MPAndroidChart折線圖(LineChart)的使用,可以左右滑動

Android統計圖表MPAndroidChart:動態添加數據更新【6】

Android圖表控件MPAndroidChart——曲線圖LineChart(多條曲線)動態添加數據

Android圖表控件MPAndroidChart的簡單介紹(MPAndroidChart3.0)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章