Android图表控件MPAndroidChart(折线图、柱状图)

一、效果

实现效果:x轴间距固定不变,y轴不显示,手指向前滑动实现多条数据的展示,双击不放大,大小固定,屏幕最多展示7个点。
问题:次代码若将y轴显示,x轴会出问题


e9dd8d4736bd6ed8df3904778c750d6.jpg

二、步骤

1.添加依赖

在project的build.gradle中引入

repositories {
      maven { url 'https://jitpack.io' }
}

在app的build.gradle中引入

dependencies {
    implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0'
}

2.调用页布局文件




    
     

            

            
      

        

        

   

三、折线图

1.封装类

import android.graphics.Color;
import android.graphics.Matrix;

import com.github.mikephil.charting.charts.Chart;
import com.github.mikephil.charting.charts.LineChart;
import com.github.mikephil.charting.components.Description;
import com.github.mikephil.charting.components.Legend;
import com.github.mikephil.charting.components.XAxis;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.data.LineData;
import com.github.mikephil.charting.data.LineDataSet;
import com.github.mikephil.charting.formatter.ValueFormatter;

import java.text.DecimalFormat;
import java.util.List;

/**
 * 折线图表
 */
public class LineChartUtils {

    /**
     * 初始化图表
     *
     * @param chart 原始图表
     * @return 初始化后的图表
     */
    public static LineChart initChart(LineChart chart, boolean isXEnbale, boolean isLeftYEnable, boolean isRightYEnable) {
        // 不显示表格颜色
        chart.setDrawGridBackground(false);
        chart.setDrawBorders(false);
        chart.setDragEnabled(true);//是否可以用手指移动图表
        chart.setScaleEnabled(false);//设置为false以禁止通过在其上双击缩放图表。是否可以缩放图表,当屏幕一屏显示不下,希望能通过缩放或滑动图表,仅设置这个和上面那个是不行的,还需要配合Matrix来实现
        chart.setTouchEnabled(true);
        chart.animateX(1500);
        chart.setDoubleTapToZoomEnabled(false);
        //下方3个设置ScaleEnabled,DragEnabled用到,表示x轴放大4倍,y不变
//        Matrix matrix=new Matrix();
//        matrix.postScale(4.0f,0.0f);
//        chart.getViewPortHandler().refresh(matrix,chart,false);
        //禁止x轴y轴同时进行缩放
        chart.setPinchZoom(false);
        // 不显示数据描述
        Description description = chart.getDescription();
        description.setEnabled(false);
        chart.setDescription(description);

        chart.setDragDecelerationEnabled(false);//拖拽滚动时,手放开是否会持续滚动,默认是true(false是拖到哪是哪,true拖拽之后还会有缓冲)
        chart.setDragDecelerationFrictionCoef(0.88f);//与上面那个属性配合,持续滚动时的速度快慢,[0,1) 0代表立即停止。
        // 不显示图例
        Legend legend = chart.getLegend();
        legend.setEnabled(false);
        chart.setNoDataTextColor(Color.parseColor("#999999"));
        chart.setNoDataText("你还没有记录数据");
        initLineChart(chart, isXEnbale, isLeftYEnable, isRightYEnable);
        chart.invalidate();
        return chart;
    }

    /**
     * 初始化xy轴
     *
     * @param chart
     */
    public static void initLineChart(LineChart chart, boolean isXEnbale, boolean isLeftYEnable, boolean isRightYEnable) {
        setXAxisBasic(chart, isXEnbale);
        setLeftYAxisBasic(chart, isLeftYEnable);
        setRightYAxisBasic(chart, isRightYEnable);
    }

    /**
     * x轴基础设置
     *
     * @param chart
     * @param isEnable 设置x轴启用或禁用
     */
    public static void setXAxisBasic(LineChart chart, boolean isEnable) {
        //得到x轴
        XAxis xAxis = chart.getXAxis();
        //是否调用x轴
        xAxis.setEnabled(isEnable);
        xAxis.setDrawAxisLine(true);//是否绘制x轴的直线
        xAxis.setDrawGridLines(true);//是否画网格线
        xAxis.setGridColor(Color.GRAY);
        xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);// 设置x轴数据的位置
        xAxis.setTextSize(3);//设置轴标签字体大小
        xAxis.setTextColor(Color.parseColor("#999999"));//设置轴标签字体的颜色

        xAxis.setAvoidFirstLastClipping(true);//图表将避免第一个和最后一个标签条目被减掉在图表或屏幕的边缘
        //设置竖线的显示样式为虚线  lineLength控制虚线段的长度  spaceLength控制线之间的空间
        xAxis.enableGridDashedLine(10f, 10f, 0f);

    }

    /**
     * 左侧y轴基础设置
     *
     * @param chart
     * @param isEnable
     */
    public static void setLeftYAxisBasic(LineChart chart, boolean isEnable) {
        //不显示y轴左边的值
        chart.getAxisLeft().setEnabled(false);

    }

    /**
     * 右侧y轴基础设置
     *
     * @param chart
     * @param isEnable
     */
    public static void setRightYAxisBasic(LineChart chart, boolean isEnable) {
        // 不显示y轴右边的值
        chart.getAxisRight().setEnabled(false);

    }

    /**
     * x轴在点击切换后重新设置的值
     *
     * @param chart
     * @param labelCount
     * @param maximum
     * @param xRangeMaximum
     */
    public static void setXAxis(LineChart chart, int labelCount, float maximum, int xRangeMaximum) {
        chart.setScaleMinima(1.0f, 1.0f);
        chart.getViewPortHandler().refresh(new Matrix(), chart, true);
        //上面两行必须放最上面否则折线间隔失效
        XAxis xAxis = chart.getXAxis();
        xAxis.setLabelCount(labelCount, true);// 设置X轴的刻度数量,第二个参数表示是否平均分配
        xAxis.setAxisMinimum(-1f);
//        xAxis.setAxisMinimum(0f);
//        xAxis.setAxisMaximum(maximum);//设置X轴的值(最小值、最大值、然后会根据设置的刻度数量自动分配刻度显示)
        xAxis.setAxisMaximum(maximum + 1f);//设置X轴的值(最小值、最大值、然后会根据设置的刻度数量自动分配刻度显示)
        xAxis.setGranularity(1f);//设置x轴坐标之间的最小间隔(因为此图有缩放功能,X轴,Y轴可设置可缩放),放在setValueFormatter之前设置
        //设置当前图表中最多在x轴坐标线上显示的刻度线总量为6
        chart.setVisibleXRangeMaximum(xRangeMaximum);//这行必须放到下面,和setLabelCount同时设置,值-1
        chart.setScaleEnabled(false);
        chart.setDoubleTapToZoomEnabled(false);
//        chart.moveViewToX(0f);//切换时间时用来将折线图回归到0点
        chart.moveViewToX(-1f);//切换时间时用来将折线图回归到0点

    }


    /**
     * 显示无数据的提示
     *
     * @param chart
     */
    public static void NotShowNoDataText(Chart chart) {
        chart.clear();
        chart.notifyDataSetChanged();
        chart.setNoDataTextColor(Color.parseColor("#999999"));
        chart.setNoDataText("你还没有记录数据");
        chart.invalidate();
    }


    /**
     * 更新图表
     *
     * @param chart  图表
     * @param values 数据点
     */
    public static void notifyDataSetChanged(LineChart chart, List values,
                                            List datelist) {
        chart.getXAxis().setValueFormatter(new ValueFormatter() {
            @Override
            public String getFormattedValue(float value) {
                if (value<0){
                    return "";
                }
                int index = (int) value;
                if (index < 0 || index >= datelist.size()) {
//                    return "" + (int) value;
                    return "";
                }
                return datelist.get(index);
            }
        });
        chart.invalidate();
        setChartData(chart, values, LineDataSet.Mode.CUBIC_BEZIER);
    }

    /**
     * 设置图表数据
     *
     * @param chart  图表
     * @param values xy数据集合
     */
    public static void setChartData(LineChart chart, List values, LineDataSet.Mode mode) {
        LineDataSet lineDataSet;
        //getDataSetCount() 总线条数,getDataSetByIndex(0) 索引0处的xy数据的集合(30天就是30个 0-29)
        if (chart.getData() != null && chart.getData().getDataSetCount() > 0) {
            lineDataSet = (LineDataSet) chart.getData().getDataSetByIndex(0);
            lineDataSet.setValues(values);
            chart.getData().notifyDataChanged();
            chart.notifyDataSetChanged();
        } else {
            //初始化折线
            lineDataSet = new LineDataSet(values, "");
            // 设置曲线颜色
            lineDataSet.setColor(Color.parseColor("#FFCC33"));

            if (mode == null) {
                //设置曲线展示为圆滑曲线(如果不设置则默认折线)
                lineDataSet.setMode(LineDataSet.Mode.CUBIC_BEZIER);
            } else {
                lineDataSet.setMode(mode);
            }
            // 不显示坐标点的小圆点
            lineDataSet.setDrawCircles(true);
            // 是否显示坐标点的数据,折线上是否绘制数据
            lineDataSet.setDrawValues(true);
            lineDataSet.setValueTextColor(Color.RED);//数据的字体颜色
            lineDataSet.setValueTextSize(8f);//设置显示数据的值的文字大小

            lineDataSet.setLineWidth(1f);//折线的宽度
            lineDataSet.setCircleRadius(2f);//数据点的半径

            // 不显示定位线,是否禁用点击高亮线
            lineDataSet.setHighlightEnabled(false);
            lineDataSet.enableDashedHighlightLine(10f, 5f, 0f);//点击后的高亮线的显示样式
            lineDataSet.setHighlightLineWidth(2f);//设置点击交点后显示高亮线宽
            lineDataSet.setHighLightColor(Color.RED);//设置点击交点后显示交高亮线的颜色

            lineDataSet.setCircleColor(Color.RED);
            lineDataSet.setDrawFilled(false);//是否对数据范围背景进行填充
            lineDataSet.setDrawCircleHole(false);// 数据点圆是否为空心圆
            final DecimalFormat format = new DecimalFormat("###,###,##0");
            lineDataSet.setValueFormatter(new ValueFormatter() {
                @Override
                public String getFormattedValue(float value) {
                    return format.format(value);
                }
            });
            //管理数据集
            LineData data = new LineData(lineDataSet);
            chart.setData(data);
            chart.invalidate();
        }

    }
}

四、柱状图

1.封装类

import android.graphics.Color;
import android.graphics.Matrix;

import com.github.mikephil.charting.charts.BarChart;
import com.github.mikephil.charting.charts.Chart;
import com.github.mikephil.charting.components.Description;
import com.github.mikephil.charting.components.Legend;
import com.github.mikephil.charting.components.XAxis;
import com.github.mikephil.charting.data.BarData;
import com.github.mikephil.charting.data.BarDataSet;
import com.github.mikephil.charting.data.BarEntry;
import com.github.mikephil.charting.formatter.ValueFormatter;

import java.text.DecimalFormat;
import java.util.List;

/**
 * 柱状图
 */
public class BarChartUtils {
    /**
     * 初始化
     *
     * @param chart
     * @return
     */
    public static BarChart initChart(BarChart chart, boolean isXEnbale, boolean isLeftYEnable, boolean isRightYEnable) {
        chart.setDrawGridBackground(false);
        chart.setDrawBorders(false);
        chart.setDragEnabled(true);
        chart.setScaleEnabled(false);
        chart.setTouchEnabled(true);
        chart.animateX(1500);
        chart.setDoubleTapToZoomEnabled(false);
        chart.setPinchZoom(false);
        Description description = chart.getDescription();
        description.setEnabled(false);
        chart.setDescription(description);
        chart.setDragDecelerationEnabled(false);
        chart.setDragDecelerationFrictionCoef(1f);
        //        chart.setMaxVisibleValueCount();
        chart.setDrawBarShadow(false);

        // 不显示图例
        Legend legend = chart.getLegend();
        legend.setEnabled(false);
        chart.setNoDataTextColor(Color.parseColor("#999999"));
        chart.setNoDataText("你还没有记录数据");
        initLineChart(chart, isXEnbale, isLeftYEnable, isRightYEnable);
        chart.invalidate();
        return chart;
    }

    /**
     * 初始化xy轴
     *
     * @param chart
     */
    public static void initLineChart(BarChart chart, boolean isXEnbale, boolean isLeftYEnable, boolean isRightYEnable) {
        setXAxisBasic(chart, isXEnbale);
        setLeftYAxisBasic(chart, isLeftYEnable);
        setRightYAxisBasic(chart, isRightYEnable);
    }

    /**
     * x轴基础设置
     *
     * @param chart
     * @param isEnable 设置x轴启用或禁用
     */
    public static void setXAxisBasic(BarChart chart, boolean isEnable) {
        //得到x轴
        XAxis xAxis = chart.getXAxis();
        //是否调用x轴
        xAxis.setEnabled(isEnable);
        xAxis.setDrawAxisLine(true);//是否绘制x轴的直线
        xAxis.setDrawGridLines(true);//是否画网格线
        xAxis.setGridColor(Color.GRAY);
        xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);// 设置x轴数据的位置
        xAxis.setTextSize(3);//设置轴标签字体大小
        xAxis.setTextColor(Color.parseColor("#999999"));//设置轴标签字体的颜色

        xAxis.setAvoidFirstLastClipping(true);//图表将避免第一个和最后一个标签条目被减掉在图表或屏幕的边缘
        //设置竖线的显示样式为虚线  lineLength控制虚线段的长度  spaceLength控制线之间的空间
        xAxis.enableGridDashedLine(10f, 10f, 0f);

    }

    /**
     * 左侧y轴基础设置
     *
     * @param chart
     * @param isEnable
     */
    public static void setLeftYAxisBasic(BarChart chart, boolean isEnable) {
        //不显示y轴左边的值
        chart.getAxisLeft().setEnabled(false);

    }

    /**
     * 右侧y轴基础设置
     *
     * @param chart
     * @param isEnable
     */
    public static void setRightYAxisBasic(BarChart chart, boolean isEnable) {
        // 不显示y轴右边的值
        chart.getAxisRight().setEnabled(false);

    }

    /**
     * x轴在点击切换后重新设置的值
     *
     * @param chart
     * @param labelCount
     * @param maximum
     * @param xRangeMaximum
     */
    public static void setXAxis(BarChart chart, int labelCount, float maximum, int xRangeMaximum) {
        chart.setScaleMinima(1.0f, 1.0f);
        chart.getViewPortHandler().refresh(new Matrix(), chart, true);
        //上面两行必须放最上面否则折线间隔失效
        XAxis xAxis = chart.getXAxis();
        xAxis.setLabelCount(labelCount, true);// 设置X轴的刻度数量,第二个参数表示是否平均分配
        xAxis.setAxisMinimum(-1f);
//        xAxis.setAxisMinimum(0f);
//        xAxis.setAxisMaximum(maximum);//设置X轴的值(最小值、最大值、然后会根据设置的刻度数量自动分配刻度显示)
        xAxis.setAxisMaximum(maximum + 1f);//设置X轴的值(最小值、最大值、然后会根据设置的刻度数量自动分配刻度显示)
        xAxis.setGranularity(1f);//设置x轴坐标之间的最小间隔(因为此图有缩放功能,X轴,Y轴可设置可缩放),放在setValueFormatter之前设置
        xAxis.setCenterAxisLabels(false);
        //设置当前图表中最多在x轴坐标线上显示的刻度线总量为6
        chart.setVisibleXRangeMaximum(xRangeMaximum);//这行必须放到下面,和setLabelCount同时设置,值-1
        chart.setScaleEnabled(false);
        chart.setDoubleTapToZoomEnabled(false);
        chart.moveViewToX(-1f);//切换时间时用来将折线图回归到0点
//        chart.moveViewToX(0f);//切换时间时用来将折线图回归到0点
    }


    /**
     * 更新图表
     *
     * @param chart  图表
     * @param values 数据点
     */
    public static void notifyDataSetChanged(BarChart chart, List values,
                                            List datelist) {

        chart.getXAxis().setValueFormatter(new ValueFormatter() {
            @Override
            public String getFormattedValue(float value) {
                if (value < 0) {
                    return "";
                }
                int index = (int) value;
                if (index < 0 || index >= datelist.size()) {
//                    return "" + (int) value;
                    return "";
                }
                return datelist.get(index);
            }
        });
        chart.invalidate();
        setChartData(chart, values);
    }

    /**
     * 设置图表数据
     *
     * @param chart  图表
     * @param values xy数据集合
     */
    public static void setChartData(BarChart chart, List values) {
        BarDataSet lineDataSet;
        //getDataSetCount() 总线条数,getDataSetByIndex(0) 索引0处的xy数据的集合(30天就是30个 0-29)
        if (chart.getData() != null && chart.getData().getDataSetCount() > 0) {
            lineDataSet = (BarDataSet) chart.getData().getDataSetByIndex(0);
            lineDataSet.setValues(values);
            chart.getData().notifyDataChanged();
            chart.notifyDataSetChanged();
        } else {
            //初始化折线
            lineDataSet = new BarDataSet(values, "");
            //设置多彩
            lineDataSet.setColors(Color.parseColor("#FFCC33"));
            // 是否显示坐标点的数据,折线上是否绘制数据
            lineDataSet.setDrawValues(true);
            lineDataSet.setValueTextColor(Color.RED);//数据的字体颜色
            lineDataSet.setValueTextSize(8f);//设置显示数据的值的文字大小

            // 不显示定位线,是否禁用点击高亮线
            lineDataSet.setHighlightEnabled(false);
            lineDataSet.setHighLightColor(Color.RED);//设置点击交点后显示交高亮线的颜色

            final DecimalFormat format = new DecimalFormat("###,###,##0");
            lineDataSet.setValueFormatter(new ValueFormatter() {
                @Override
                public String getFormattedValue(float value) {
                    return format.format(value);
                }
            });

            //管理数据集
            BarData data = new BarData(lineDataSet);
            data.setBarWidth(0.5f);
            chart.setFitBars(true);//是否处理超出的柱块(这是个非常重要的属性,有时候可以帮助我们自动处理超出的柱块),一般都会加上
            chart.setData(data);
            chart.invalidate();
        }

    }

    /**
     * 显示无数据的提示
     *
     * @param chart
     */
    public static void NotShowNoDataText(Chart chart) {
        chart.clear();
        chart.notifyDataSetChanged();
        chart.setNoDataTextColor(Color.parseColor("#999999"));
        chart.setNoDataText("你还没有记录数据");
        chart.invalidate();
    }
}

五、折线图柱状图的调用

public class Activity extends AppCompatActivity {
    private ActivityLayoutBinding mBinding;
    private int xLableCount = 7;
    private int xRangeMaximum = xLableCount - 1;


    private List netLineList = new ArrayList<>();
    private List netBarList = new ArrayList<>();
    private List netDateList = new ArrayList<>();

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        mBinding = DataBindingUtil.setContentView(this, R.layout.activity_layout);
         //折线图初始化
        LineChartUtils.initChart(mBinding.lineChart, true, false, false);
         //柱状图初始化
        BarChartUtils.initChart(mBinding.barChart, true, false, false);
          
         //设置数据
        setData();
     
       mBinding.rgSelector.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(RadioGroup group, int checkedId) {
                switch (checkedId) {
                    case R.id.rb_one:
                        //近7天
                        setData();
                        break;
                    case R.id.rb_two:
                        //近30天
                        setDataFor30();
                        break;            
                    default:
                        break;
                }
            }
        });

}

 /**
     * 获取默认查询的时间(当前时间的前day天)
     */
    public static String formatDatas(int day) {
        Date dNow = new Date(); // 当前时间
        Date dBefore = new Date();
        Calendar calendar = Calendar.getInstance(); // 得到日历
        calendar.setTime(dNow);// 把当前时间赋给日历
        calendar.add(Calendar.DAY_OF_MONTH, -day); // 设置为前三天
        dBefore = calendar.getTime(); // 得到前三天的时间
//        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); // 设置时间格式
        SimpleDateFormat sdf = new SimpleDateFormat("MM-dd"); // 设置时间格式
        String defaultStartDate = sdf.format(dBefore); // 格式化
        return defaultStartDate;

    }



   /**
    *    new Entry(x,y) x: 折线图中数据值的位置索引 y: 具体数据值
    */  

  private void setData() {
        netLineList.clear();
        netBarList.clear();
        netDateList.clear();
        String s;
        SimpleDateFormat dateFormat1 = new SimpleDateFormat(
                "MM-dd");
        Calendar c = Calendar.getInstance();
        String currentDate = dateFormat1.format(c.getTime());
        netDateList.add(currentDate);
        for (int i = 1; i < 7; i++) {
            s = formatDatas(i);
            netDateList.add(s);
        }
        Collections.reverse(netDateList);

        float[] lineFloat = {11, 15, 16, 17, 16, 16, 12};
        for (int i = 0; i < netDateList.size(); i++) {
//            netLineList.add(new Entry((float) i, (float) Math.random() * 80));
            netLineList.add(new Entry((float) i, lineFloat[i]));
            netBarList.add(new BarEntry((float) i, lineFloat[i]));
        }

       xLableCount = (netDateList.size() + 3) > 7 ? 7 : (netDateList.size() + 3);
       xRangeMaximum = xLableCount - 1;
     
        LineChartUtils.setXAxis(mBinding.lineChart, xLableCount, netDateList.size(), xRangeMaximum);
        LineChartUtils.notifyDataSetChanged(mBinding.lineChart, netLineList, netDateList);
        BarChartUtils.setXAxis(mBinding.barChart, xLableCount, netDateList.size(), xRangeMaximum);
        BarChartUtils.notifyDataSetChanged(mBinding.barChart, netBarList, netDateList);
                       
        //无数据
        //LineChartUtils.NotShowNoDataText(mBinding.lineChart);
        //BarChartUtils.NotShowNoDataText(mBinding.barChart);

    }

 private void setDataFor30() {
       netLineList.clear();
        netBarList.clear();
        netDateList.clear();
        String s2;
        SimpleDateFormat dateFormat2 = new SimpleDateFormat(
                "MM-dd");
        Calendar c2 = Calendar.getInstance();
        String currentDate2 = dateFormat2.format(c2.getTime());
        netDateList.add(currentDate2);
        for (int i = 1; i < 30; i++) {
            s2 = formatDatas(i);
            netDateList.add(s2);
        }
        Collections.reverse(netDateList);


        float[] lineFloat = {14, 15, 16, 17, 16, 16, 12, 14, 15, 16, 17, 16, 16, 12, 14, 15, 16, 17, 16, 16, 12, 14, 15, 16, 17, 16, 16, 12, 14, 15};
        for (int i = 0; i < netDateList.size(); i++) {

//            netLineList.add(new Entry((float) i, (float) Math.random() * 80));
//            netBarList.add(new BarEntry((float) i, (float) Math.random() * 80));
            netLineList.add(new Entry((float) i,  lineFloat[i]));
            netBarList.add(new BarEntry((float) i,  lineFloat[i]));

        }

       xLableCount = (netDateList.size() + 3) > 7 ? 7 : (netDateList.size() + 3);
       xRangeMaximum = xLableCount - 1;
     
        LineChartUtils.setXAxis(mBinding.lineChart, xLableCount, netDateList.size(), xRangeMaximum);
        LineChartUtils.notifyDataSetChanged(mBinding.lineChart, netLineList, netDateList);
        BarChartUtils.setXAxis(mBinding.barChart, xLableCount, netDateList.size(), xRangeMaximum);
        BarChartUtils.notifyDataSetChanged(mBinding.barChart, netBarList, netDateList);
                       
        //无数据
        //LineChartUtils.NotShowNoDataText(mBinding.lineChart);
        //BarChartUtils.NotShowNoDataText(mBinding.barChart);

   }

}

参考
(1条消息) Android图表控件MPAndroidChart之线形图表介绍(LineChart)_盒Beauty的博客-CSDN博客_android linechart

(1条消息) MpAndroidChart-LineChart 折线图使用(含动态添加点,动态添加曲线)_0729Liang-CSDN博客

(1条消息) MPAndroidChart 教程:数据格式器 ValueFormatter(五)_庄宏基的博客-CSDN博客

Android MPAndroidChart使用,X轴标签换行显示 - (jianshu.com)

实现柱状图与条形图的结合,MPAndroidChart 的简单使用 (juejin.cn)

你可能感兴趣的:(Android图表控件MPAndroidChart(折线图、柱状图))