目录

零、简介

一、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)

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐