最近闲来无事,总结下Android的MPAndroidChart组件,这个组件对于绘图来说,可以说是非常方便了,本文包括柱形图,折线图,饼状图,动态折线图等的基本使用

首先

首先是导入依赖,除了MPAndroidChart所需的依赖包,我还导入了butterknife的包,可以用于绑定视图;
1.projectde gradle

repositories {
        google()
        //加上如下
        maven { url "https://jitpack.io" }
        jcenter()
    }

2.module的gradle
在依赖中加入如下,

//MPAndroidChart依赖
    implementation 'com.github.PhilJay:MPAndroidChart:v3.0.3'
    implementation 'com.jakewharton:butterknife:10.0.0'
    annotationProcessor 'com.jakewharton:butterknife-compiler:10.0.0'

必须指定jdk版本,否则编译会报错的

compileOptions {
            sourceCompatibility JavaVersion.VERSION_1_8
            targetCompatibility JavaVersion.VERSION_1_8
        }

在使用的时候必须要先**ButterKnife.bind(this);**绑定这个Activity,然后可以通过@OnClick和@BindView注解绑定视图和事件

动态折线图

先上效果图:

android 绘制折线动画 android折线图_移动开发

android 绘制折线动画 android折线图_安卓_02


布局文件

**布局文件**

```xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.github.mikephil.charting.charts.LineChart
        android:id="@+id/dy_line_chart"
        android:layout_width="match_parent"
        android:layout_height="400dp"
        android:layout_marginTop="50dp"
        android:layout_weight="1"/>

</LinearLayout>

图1,通过工具类进行操作,每隔一秒进行插入数据,最多显示10个,当超过十个的时候,x轴会向左偏移,但页面超过10个点的时候可以滑动,查看之前的(没想好如何解决
图2,通过当数据更新的时候,去刷新页面,实现动态的效果,当超过10的时候,将数据往往前移动一位,重新赋值,保证页面只显示最新的10个点(因为会频繁的创建对象,不知道会不会导致内存溢出

方式一

所需要的工具类代码:

/**
 * 动态折线图工具类
 */
public class DyLineChartUtils {

    private LineChart lineChart;
    private YAxis leftAxis;
    private XAxis xAxis;
    private LineData lineData;
    private LineDataSet lineDataSet;
    private List<String> timeList = new ArrayList<>(); //存储x轴的时间
    private Context context;

    public DyLineChartUtils(LineChart mLineChart, String name, int color, Context con) {
        this.context=con;
        this.lineChart = mLineChart;
        leftAxis = lineChart.getAxisLeft();
        xAxis = lineChart.getXAxis();
        initLineChart();
        initLineDataSet(name, color);
    }
    /**
     * 初始化LineChart
     */
    private void initLineChart() {
        lineChart.setDoubleTapToZoomEnabled(false);
        // 不显示数据描述
        lineChart.getDescription().setEnabled(false);
        // 没有数据的时候,显示“暂无数据”
        lineChart.setNoDataText("暂无数据");
        //禁止x轴y轴同时进行缩放
        lineChart.setPinchZoom(false);
        //启用/禁用缩放图表上的两个轴。
        lineChart.setScaleEnabled(false);
        //设置为false以禁止通过在其上双击缩放图表。
        lineChart.getAxisRight().setEnabled(false);//关闭右侧Y轴
        lineChart.setDrawGridBackground(false);
        //显示边界
        lineChart.setDrawBorders(true);
        //折线图例 标签 设置 这里不显示图例
        Legend legend = lineChart.getLegend();
        legend.setEnabled(false);

        //X轴设置显示位置在底部
        xAxis.setEnabled(false);//关闭x轴
        xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
        xAxis.setGranularity(1f);
        xAxis.setLabelCount(10);
        xAxis.setDrawGridLines(false); // 不绘制网格线
        xAxis.setValueFormatter(new IAxisValueFormatter() {
            @Override
            public String getFormattedValue(float value, AxisBase axis) {
                return "";
            }
        });
        //保证Y轴从0开始,不然会上移一点
        leftAxis.setAxisMinimum(0f);
        leftAxis.setDrawGridLines(false);
    }

    /**
     * 初始化折线(一条线)
     *
     * @param name
     * @param color
     */
    private void initLineDataSet(String name, int color) {
        lineDataSet = new LineDataSet(null, name);
        lineDataSet.setLineWidth(1.5f);
        lineDataSet.setCircleRadius(3f);
        lineDataSet.setColor(color);
        lineDataSet.setCircleColor(color);
        lineDataSet.setHighLightColor(color);
        //设置曲线填充
        lineDataSet.setDrawFilled(true);//填充底部颜色
        lineDataSet.setAxisDependency(YAxis.AxisDependency.LEFT);
        lineDataSet.setValueTextSize(10f);
        lineDataSet.setMode(LineDataSet.Mode.LINEAR);//CUBIC_BEZIER
        //添加一个空的 LineData
        lineData = new LineData();
        lineChart.setData(lineData);

        LineChartMarkView mv = new LineChartMarkView(context, xAxis.getValueFormatter());
        mv.setChartView(lineChart);
        lineChart.setMarker(mv);
        lineChart.invalidate();

    }
    /**
     * 动态添加数据(一条折线图)
     *
     * @param number
     */
    public void addEntry(Double number) {
        //最开始的时候才添加 lineDataSet(一个lineDataSet 代表一条线)
        if (lineDataSet.getEntryCount() == 0) {
            lineData.addDataSet(lineDataSet);
        }
        lineChart.setData(lineData);
        //避免集合数据过多,及时清空(做这样的处理,并不知道有没有用,但还是这样做了)
        if (timeList.size() > 11) {
            timeList.clear();
        }
        lineDataSet.setDrawValues(false);//不显示折线上的值
        Entry entry = new Entry(lineDataSet.getEntryCount(), number.floatValue());
        lineData.addEntry(entry, 0);
        //通知数据已经改变
        lineData.notifyDataChanged();
        lineChart.notifyDataSetChanged();
        //设置在曲线图中显示的最大数量
        lineChart.setVisibleXRangeMaximum(10);
        //移到某个位置
        lineChart.moveViewToX(lineData.getEntryCount() - 5);
    }


    /**
     * 设置Y轴值
     */
    public void setYAxis(float max, float min, int labelCount) {
        if (max < min) {
            return;
        }
        leftAxis.setAxisMaximum(max);
        leftAxis.setAxisMinimum(min);
        leftAxis.setLabelCount(labelCount, false);
        lineChart.invalidate();
    }
}

在这里我设置了个markView,当点击折线图的点时,会浮窗显示对应y轴的数据代码很简单:
布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@drawable/shape_gary"
    android:orientation="vertical">

    <TextView
        android:id="@+id/tv_value"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp"
        android:textColor="@android:color/white" />

</LinearLayout>

java代码:

public class LineChartMarkView extends MarkerView {

    private TextView tvValue;
    private IAxisValueFormatter xAxisValueFormatter;
    public LineChartMarkView(Context context, IAxisValueFormatter xAxisValueFormatter) {
        super(context, R.layout.layout_markview);
        this.xAxisValueFormatter = xAxisValueFormatter;
        tvValue = findViewById(R.id.tv_value);
    }
 
    @SuppressLint("SetTextI18n")
    @Override
    public void refreshContent(Entry e, Highlight highlight) {
        super.refreshContent(e, highlight);
        tvValue.setText(e.getY()+"");
    }
 
    @Override
    public MPPointF getOffset() {
        return new MPPointF(-(getWidth() / 2), -getHeight());
    }
}

剩下的就是调用了,在Activity中直接使用即可

public class DyLineChartActivity  extends Activity {
    @BindView(R.id.dy_line_chart)
    LineChart lineChart;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.mp_dy_line_chart);
        ButterKnife.bind(this);

        //方式1
        initWay1();
        //方式2
//        initWay2();
    }

    /**
     * 通过工具类,动态添加数据,不断使x轴偏移
     */
    public void initWay1(){
        //1、创建工具类对象
        DyLineChartUtils dy = new DyLineChartUtils(lineChart,"", Color.RED,this);
        //2.设置最大值
        dy.setYAxis(40,0,5);
        //3.添加数据
        //死循环查询数据
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            double v = (Math.random() * 20) + 20;
                            dy.addEntry(v);
                        }
                    });
                }
            }
        }).start();
    }

方式二

方式二是在一的基础上去改的,实现了只保留10条最新的记录
更新下代码,将代码抽出一个工具类,方便使用

/**
 * 动态折线图工具类
 */
public class DyLineChartUtils {

    LineChart lineChart;
    private YAxis yAxis;
    private XAxis xAxis;
    private List<Entry> entries;
    private LineData lineData;
    private LineDataSet lineDataSet;
    private Context context;

    /**
     * @param mLineChart chart对象
     * @param name 折线名字
     * @param color 折线的颜色
     * @param mContext
     * @param max y轴最大值
     * @param min y轴最小值
     * @param labelCount 点的个数
     */
    public DyLineChartUtils(LineChart mLineChart, String name, int color, Context mContext,float max, float min, int labelCount) {
        this.context=mContext;
        this.lineChart = mLineChart;
        entries=new ArrayList<>();
        initLineChart();
        setYAxis(max,min,labelCount);
        initLineDataSet(name,color);
    }

    /**
     * 通过不断的刷新数据
     */
    public void initLineChart(){
        //显示边界
        lineChart.setDrawBorders(true);
        // 不显示数据描述
        lineChart.getDescription().setEnabled(false);
        //禁止x轴y轴同时进行缩放
        lineChart.setPinchZoom(false);
        lineChart.getAxisRight().setEnabled(false);//关闭右侧Y轴
        lineChart.setDrawGridBackground(false);
        Legend legend = lineChart.getLegend();
        legend.setEnabled(false);
        //获取x,y轴
        yAxis = lineChart.getAxisLeft();
        xAxis = lineChart.getXAxis();
        //设置x,y轴
        xAxis.setEnabled(false);//关闭x轴
        //保证Y轴从0开始,不然会上移一点
        yAxis.setAxisMinimum(0f);
        yAxis.setDrawGridLines(false);
    }

    /**
     * 初始化dataset
     * @param name
     * @param color
     */
    private void initLineDataSet(String name,int color) {
        if(entries==null){
            entries= new ArrayList<>();
            entries.add(new Entry(entries.size(),0));
        }
        //一个LineDataSet就是一条线
        lineDataSet = new LineDataSet(null, name);
        lineDataSet.setLineWidth(1.5f);
        lineDataSet.setCircleRadius(3f);
        lineDataSet.setColor(color);
        lineDataSet.setCircleColor(color);
        lineDataSet.setHighLightColor(color);
        //设置曲线填充
        lineDataSet.setDrawFilled(true);//填充底部颜色
        lineDataSet.setAxisDependency(YAxis.AxisDependency.LEFT);
        lineDataSet.setValueTextSize(10f);
        lineDataSet.setMode(LineDataSet.Mode.CUBIC_BEZIER);//CUBIC_BEZIER
        LineChartMarkView mv = new LineChartMarkView(context, xAxis.getValueFormatter());
        mv.setChartView(lineChart);
        lineChart.setMarker(mv);

        lineData = new LineData();
        lineChart.setData(lineData);
    }

    /**
     * 设置y轴的值
     * @param max
     * @param min
     * @param labelCount
     */
    public void setYAxis(float max, float min, int labelCount) {
        if (max < min) {
            return;
        }
        yAxis.setAxisMaximum(max);
        yAxis.setAxisMinimum(min);
        yAxis.setLabelCount(labelCount, false);
    }

    /**
     * 添加数据,只保留10个
     * @param number
     */
    public void addEntry(Double number) {
        //只保留最新的10个,超过时,将第一个移除,其他的向前移动
        if(entries.size()>=10){
            entries.remove(0);
            for (int i=0;i<entries.size();i++){
                Entry entry = entries.get(i);
                entry.setX(i-1);
                entries.set(i,entry);
            }
        }

        //将最新的添加进去,
        entries.add(new Entry(entries.size(),number.floatValue()));
        lineDataSet.setValues(entries);
        //不显示折线上的值
        lineDataSet.setDrawValues(false);
        lineData=new LineData(lineDataSet);
        lineChart.setData(lineData);
        lineChart.notifyDataSetChanged();//对图表数据进行更新
        lineChart.invalidate();
    }

}

Activity中只用于调用

public class DyLineChartActivity  extends Activity {
    @BindView(R.id.dy_line_chart)
    LineChart lineChart;
    DyLineChartUtils dy;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.mp_dy_line_chart);
        ButterKnife.bind(this);
        initView();
        getLineChart();
    }
    private void initView() {
        lineChart=(LineChart)findViewById(R.id.chart);

        dy=new DyLineChartUtils(lineChart,"体温",Color.CYAN,this,40,0,5);
       
    }


    public void getLineChart() {
        //死循环查询数据
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    try {
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            double value = (Math.random() * 20) + 15;
                            dy.addEntry(value);
                            Log.i("info", "此时value的值为===============>"+value);
                        }
                    });
                }
            }
        }).start();
    }
}

如果有什么问题欢迎讨论,有什么错误欢迎指出