结合项目经验来谈使用MPAndoridChart的总结(二)

上一篇文章我们具体介绍了使用MPAndroidChart来如何画饼图,结合项目经验来谈使用MPAndoridChart的总结(一)
这篇文章我们来看看如何画折线图。
画折线图
在这里插入图片描述
效果如上。
我们使用LineChart这个类。
1、在布局文件中,

<com.github.mikephil.charting.charts.LineChart
                            android:id="@+id/lineChart"
                            android:layout_width="match_parent"
                            android:layout_height="250dp"/>

2、java代码,
我们可以根据我们最终想要的效果进行一系列的设置。
下面举例:
lineChart.setDrawBorders(true); //启用后,将渲染边框矩形。如果启用此选项,则无法绘制x轴和y轴的轴线。默认为false。
lineChart.setAutoScaleMinMaxEnabled(true); //指示是否启用y轴上的自动缩放的标志。这对于显示财务数据的图表尤其有用。默认为false。

注:Chart是PieChart和LineChart的基类,类似于setExtraLeftOffset、getDescription这些方法是Chart中的方法,因此PieChart和LineChart都可以调用。
涉及到折线图,那就必须讲到x轴和y轴了,x轴和y轴分别对应的类是XAxis和YAxis。
X轴只有一条,Y轴有两条。

XAxis xAxis = lineChart.getXAxis();  //得到X轴
YAxis leftYAxis = lineChart.getAxisLeft();  //得到左侧的Y轴
YAxis rightYAxis = lineChart.getAxisRight();  //得到右侧的Y轴
想要隐藏,只需调用setEnabled(false)即可。
xAxis.setEnabled(false);  //不显示X轴
leftYAxis.setEnabled(false);  //不显示左侧Y轴
rightYAxis.setEnabled(false);  //不显示右侧Y轴

xAxis.setPosition(XAxis.XAxisPosition.BOTTOM); //设置X轴的位置在下方,默认在上方
对应的源码如下:

    /**
     * sets the position of the x-labels
     *
     * @param pos
     */
    public void setPosition(XAxisPosition pos) {
        mPosition = pos;
    }

    /**
     * the position of the x-labels relative to the chart
     */
    private XAxisPosition mPosition = XAxisPosition.TOP;

xAxis.setDrawGridLines(false); //设置不显示X轴对应的网格线(即垂直方向上的网格线),默认是显示的
leftYAxis.setDrawGridLines(false); //设置不显示左侧Y轴对应的网格线(即水平方向上的网格线),默认是显示的

接下来我们来看另外一个类:LineDataSet,一个LineDataSet对应一条折线/曲线(这里我们可以通过设置来指定线的效果)。
我们可以通过LineDataSet的构造方法得到LineDataSet的实例。

LineDataSet(List<Entry> yVals, String label)  //LineDataSet的构造方法

lineDataSet.setColor(Color.parseColor("#3bb4fd")); //设置线的颜色
lineDataSet.setLineWidth(1.6f); //设置线的宽度
lineDataSet.setDrawCircles(true); //设置显示圆点(即线条中的顶点/峰点),默认为true
对应的源码如下:

    /**
     * set this to true to enable the drawing of circle indicators for this
     * DataSet, default true
     *
     * @param enabled
     */
    public void setDrawCircles(boolean enabled) {
        this.mDrawCircles = enabled;
    }

    /**
     * if true, drawing circles is enabled
     */
    private boolean mDrawCircles = true;

lineDataSet.setDrawCircleHole(false); //设置显示实心圆点,默认为false
对应的源码如下:

    /**
     * Set this to true to allow drawing a hole in each data circle.
     *
     * @param enabled
     */
    public void setDrawCircleHole(boolean enabled) {
        mDrawCircleHole = enabled;
    }

    private boolean mDrawCircleHole = true;

lineDataSet.setCircleColor(Color.BLUE); //设置圆点的颜色
lineDataSet.setMode(LineDataSet.Mode.LINEAR); //设置线条的绘制模式,默认为折线。
对应的源码如下:

    /**
     * Returns the drawing mode for this LineDataSet
     *
     * @return
     */
    public void setMode(LineDataSet.Mode mode) {
        mMode = mode;
    }

    /**
     * Drawing mode for this line dataset
     **/
    private LineDataSet.Mode mMode = Mode.LINEAR;

上面讲的都是针对折线图UI上进行设置
下面我们来看如何将我们的数据通过折线图展示出来
其实上面也略有介绍到,其实主要是三步:
第一步:得到LineDataSet对象。
第二步:得到LineData对象。
第三步:设置数据,lineChart.setData(lineData);
我们下面给出示例代码:

LineDataSet lineDataSet = new LineDataSet(entries, "");  //得到LineDataSet对象,构造方法中的第一个参数是源数据,第二个参数是label,label我们直接传一个空字符串即可。
LineData data = new LineData(lineDataSet);  //得到LineData对象。这里我们提一下:如果是画两条折线,形成双折线对比效果,又该怎么实现呢?如果是三条,或者更多呢?我们后面再看。
data.setDrawValues(false);  //折线图不显示数值
lineChart.setData(data);  //设置数据

自定义x轴:
示例代码如下:

//1、声明并初始化存储x轴坐标的数组
final String[] xValues = new String[length];  //这里的length取决于业务
//2、x轴坐标赋值,并实例化Entry。sourceList为源数据。Entry表示图表中一个条目,在这里可以理解为一个点。
List<Entry> entries = new ArrayList<Entry>();
for (int i = 0; i < sourceList.size(); i++)  {
      xValues[i] = sourceList.get(i).getDateTime();
      entries.add(new Entry(i, sourceList.get(i).getCounts()));
}
IAxisValueFormatter formatter = new IAxisValueFormatter() {
      @Override
      public String getFormattedValue(float value, AxisBase axis) {
            if (value < (float) xValues.length) {
                return xValues[(int) value];
            } else {
                 return "";
            }
      }
}
xAxis.setValueFormatter(formatter);

下面我们再看一个项目中的真实效果图:
在这里插入图片描述
我们再来看下这个应该怎么实现。这次我们直接上代码(注:下面代码中使用到的OutletCheckItem是与业务相关的一个实体类,我们这里不用去管它):

private void drawLineChart(List<OutletCheckItem> lastWeekOutletCheckItemList, int lastWeekColor, List<OutletCheckItem> currentWeekOutletCheckItemList, int currentColor) {
      Legend legend = lineChart.getLegend();  //得到图例
      legend.setForm(Legend.LegendForm.CIRCLE);  //设置形状为圆形
      legend.setPosition(Legend.LegendPosition.ABOVE_CHART_RIGHT);  //设置图例的位置为图表的右上方
      legend.setOrientation(Legend.LegendOrientation.VERTICAL);  //设置图例条目垂直排列
      lineChart.getDescription().setEnabled(false);  //隐藏描述
      lineChart.setNoDataText("暂无数据");  //无数据时显示的文字
      lineChart.setScaleEnabled(false);  //禁止缩放
      lineChart.setTouchEnabled(false);  //禁止触摸

      final String[] xValues = new String[]{"周日", "周一", "周二", "周三", "周四", "周五", "周六"};
      XAxis xAxis = lineChart.getXAxis();
      xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
      xAxis.setGranularity(1f);  //设置x轴坐标之间的最小间隔
      //设置x轴的值(最小值、最大值,然后会根据设置的刻度数量自动分配刻度显示)
      xAxis.setAxisMinmum(0f);
      xAxis.setAxisMaximum(xValues.length);
      xAxis.setDrawGridLines(false);  //不显示网格线
      IAxisValueFormatter formatter = new IAxisValueFormatter() {
            @Override
            public String getFormattedValue(float value, AxisBase axis) {
                   if (value < (float) xValues.length) {
                       return xValues[(int) value];
                   } else {
                        return "";
                   }
            }
      };
      xAxis.setValueFormatter(formatter);  //自定义x轴
      
      YAxis yAxis = lineChart.getAxisLeft();  //得到左侧Y轴
      lineChart.getAxisRight().setEnabled(false);  //右侧Y轴不显示
      yAxis.setEnabled(false);  //左侧Y轴不显示
      yAxis.setAxisMinimum(0f);  //设置Y轴的最小值
      
      LineDataSet currentWeekLineDataList = getLineDataSet(currentWeekOutletCheckItemList, currentWeekColor, 1, "本周数据");  //得到本周折线图对应的LineDataSet对象
      LineDataSet lastWeekLineDataSet = getLineDataSet(lastWeekOutletCheckItemList, lastWeekColor, 0, "上周数据");  //得到上周折线图对应的LineDataSet对象
      List<ILineDataSet> lineDataSets = new ArrayList<ILineDataSet>();
      lineDataSets.add(currentWeekLineDataSet);
      lineDataSets.add(lastWeekLineDataSet);
      LineData lineData = new LineData(lineDataSets);  //得到LineData对象
      lineData.setDrawValues(true);  //折线图上显示值
      lineChart.invalidate();  
}

private LineDataSet getLineDataSet(List<OutletCheckItem> outletCheckItemList, int color, int type, String label) {
      for (int i = 0; i < outletCheckItemList.size(); i++) {
           OutletCheckItem outletCheckItem = outletCheckItemList.get(i);
           String theDayOfTheWeek = TimeUtils.getTheDayOfTheWeek(outletCheckItem.getDateTime(), "yyyy-MM-dd");  //得到日期的星期表示,即将"yyyy-MM-dd HH:mm:ss"的表示改成"周一"的这种表示
           outletCheckItem.setDataTime(theDayOfTheWeek);
      }
      List<Entry> entries = new ArrayList<Entry>();
      final String xValues;
      if (type == 0) {  //上周
          xValues = new String[]{"周日", "周一", "周二", "周三", "周四", "周五", "周六"};
      } else {  //本周
           Calendar calendar = Calendar.getInstance();
           int week = calendar.get(Calendar.DAY_OF_WEEK);
           switch (week) {
                 case 1:
                        xValues = new String[]{"周日", "周一", "周二", "周三", "周四", "周五", "周六"};
                        break;
                 case 2:
                        xValues = new String[]{"周日", "周一"};
                        break;
                 case 3:
                        xValues = new String[]{"周日", "周一", "周二"};
                        break;
                 case 4:
                        xValues = new String[]{"周日", "周一", "周二", "周三"};
                        break;
                 case 5:
                        xValues = new String[]{"周日", "周一", "周二", "周三", "周四"};               
                        break;
                  case 6:
                        xValues = new String[]{"周日", "周一", "周二", "周三", "周四", "周五"};
                        break;
                  case 7:
                        xValues = new String[]{"周日", "周一", "周二", "周三", "周四", "周五", "周六"};
                        break;
                   default:
                        xValues = new String[]{"周日", "周一", "周二", "周三", "周四", "周五", "周六"};
                        break;                                   
           }
      }
      for (int i = 0; i < xValues.length; i++) {
           boolean bl = false;
           for (int j = 0; j < outletCheckItemList.size(); j++) {
                if (xValues[i].equals(outletCheckItemList.get(j).getDateTime())) {
                    entries.add(new Entry(i, outletCheckItemList.get(j).getCounts()));
                    bl = true;
                    break;
                }
           }
           if (!bl) {
               entries.add(new Entry(i, 0));
           }
      }
      LineDataSet lineDataSet = new LineDataSet(entries, label);
      lineDataSet.setColor(color);
      lineDataSet.setLineWidth(2f);
      lineDataSet.setDrawCircles(true);
      lineDataSet.setDrawCircleHole(false);
      lineDataSet.setCircleColor(color);
      lineDataSet.setMode(LineDataSet.Mode.LINEAR);
      lineDataSet.setValueFormatter(new IValueFormatter() {
              @Override
              public String getFormattedValue(float value, Entry entry, int dataSetIndex, ViewPortHandler viewPortHandler) {
                     return "" + (int) value;
              }
      });
      return lineDataSet;
}

下面我们再来看一个项目中的真实效果图:
在这里插入图片描述
在这里插入图片描述
我们还是直接上代码:
注:图表上方一行是使用基本布局来实现的

privite int mMaxCount = 0;
private void drawLineChart(List lastWeekList, int lastWeekColor, List currentWeekList, int currentWeekColor) {
     lineChart.getLegend().setEnabled(false);
     lineChart.getDescription().setEnabled(false);
     lineChart.setNoDataText("暂无数据");
     lineChart.setScaleEnabled(false);  
     CustomMarkerView customMarkerView = new CustomMarkerView(this, R.layout.content_marker_view, lineChart);
     lineChart.setMarker(customMarkerView);  //设置MarkerView
     final String[] xValues = new String[]{"周日", "周一", "周二", "周三", "周四", "周五", "周六"};
     XAxis xAxis = lineChart.getXAxis();
     xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
     xAxis.setGranularity(1f);  //设置x轴坐标之间的最小间隔
     //设置x轴的值(最小值、最大值,然后会根据设置的刻度数量自动分配刻度显示)
     xAxis.setAxisMinmum(0f);
     xAxis.setAxisMaximum(xValues.length);
     xAxis.setTextColor(getResources().getColor(R.color.baseColor2));  //设置x轴坐标的颜色
     xAxis.setGridColor(getResources().getColor(R.color.dark_blue_2));  //设置x轴方向上网格线的颜色
     xAxis.setAxisLineColor(getResources().getColor(R.color.dark_blue_2));  //设置x轴的颜色
     IAxisValueFormatter formatter = new IAxisValueFormatter() {
            @Override
            public String getFormattedValue(float value, AxisBase axis) {
                if (value < (float) xValues.length) {
                    return xValues[(int) value];
                } else {
                    return "";
                }
            }
        };
        xAxis.setValueFormatter(formatter);  //自定义x轴

        YAxis yAxis = lineChart.getAxisLeft();  
        lineChart.getAxisRight().setEnabled(false);
        yAxis.setDrawGridLines(false);
        yAxis.setGranularity(1f);  //设置y轴坐标之间的最小间隔
        yAxis.setAxisMinimum(0f);  //设置y轴的最小值
        yAxis.setTextColor(getResources().getColor(R.color.baseColor2));  //设置y轴坐标的颜色
        yAxis.setAxisLineColor(getResources().getColor(R.color.dark_blue_2));  //设置y轴的颜色
        
        mMaxCount  = 0;
        LineDataSet lastWeekLineDataSet = getLineDataSet(lastWeekList, lastWeekColor, 0);
        LineDataSet currentWeekLineDataSet = getLineDataSet(currentWeekList, currentWeekColor, 1);
        yAxis.setLabelCount(5);
        yAxis.setAxisMaxium(maxCount + (5 - maxCount % 5));
        List<ILineDataSet> lineDataSets = new ArrayList<ILineDataSet>();
        lineDataSets.add(lastWeekLineDataSet);
        lineDataSets.add(currentWeekLineDataSet);
        LineData lineData = new LineData(lineDataSets);
        lineData.setDrawValues(true);
        lineChart.setData(lineData);
}

    private LineDataSet getLineDataSet(List list, int color, int timeType) {
       for (int i = 0; i < list.size(); i++) {
            if (list.get(i).getCounts() > maxCount) {
                maxCount = list.get(i).getCounts();
            }
        }

        /**
         * 再进行一次数据处理,得到一个时间线为“周一、周二...”的集合
         */
        for (int i = 0; i < list.size(); i++) {
            OutletCheckItem outletCheckItem = list.get(i);
            String theDayOfTheWeek = TimeUtils.getTheDayOfTheWeek(outletCheckItem.getDateTime(), "yyyy-MM-dd");
            outletCheckItem.setDataTime(theDayOfTheWeek);
        }

        List<Entry> entries = new ArrayList<Entry>();
        final String[] xValues;
        if (timeType == 0) {  //上周
            xValues = new String[]{"周一", "周二", "周三", "周四", "周五", "周六", "周日"};
        } else {  //本周
            Calendar calendar = Calendar.getInstance();
            int week = calendar.get(Calendar.DAY_OF_WEEK);
            switch (week) {
                case 1:
                    xValues = new String[]{"周一", "周二", "周三", "周四", "周五", "周六", "周日"};
                    break;
                case 2:
                    xValues = new String[]{"周一"};
                    break;
                case 3:
                    xValues = new String[]{"周一", "周二"};
                    break;
                case 4:
                    xValues = new String[]{"周一", "周二", "周三"};
                    break;
                case 5:
                    xValues = new String[]{"周一", "周二", "周三", "周四"};
                    break;
                case 6:
                    xValues = new String[]{"周一", "周二", "周三", "周四", "周五"};
                    break;
                case 7:
                    xValues = new String[]{"周一", "周二", "周三", "周四", "周五", "周六"};
                    break;
                default:
                    xValues = new String[]{"周一", "周二", "周三", "周四", "周五", "周六", "周日"};
                    break;
            }
        }
        for (int i = 0; i < xValues.length; i++) {
            boolean bl = false;
            for (int j = 0; j < list.size(); j++) {
                if (xValues[i].equals(list.get(j).getDateTime())) {
                    entries.add(new Entry(i, list.get(j).getCounts()));
                    bl = true;
                    break;
                }
            }
            if (!bl) {
                entries.add(new Entry(i, 0));
            }
        }
        LineDataSet lineDataSet = new LineDataSet(entries, "");  
        lineDataSet.setColor(color); 
        lineDataSet.setLineWidth(2f);  
        if (entries.size() > 1) {
            lineDataSet.setDrawCircles(false);  //不显示圆点
        } else {
            lineDataSet.setDrawCircles(true);  //显示圆点
            lineDataSet.setDrawCircleHole(false);  //显示实心点
            lineDataSet.setCircleColor(color);
        }
        lineDataSet.setHighLightColor(Color.TRANSPARENT);  //设置高亮网格线透明
        lineDataSet.setMode(LineDataSet.Mode.HORIZONTAL_BEZIER);
        lineDataSet.setValueFormatter(new IValueFormatter() {
            @Override
            public String getFormattedValue(float value, Entry entry, int dataSetIndex, ViewPortHandler viewPortHandler) {
                return "";
            }
        });
        return lineDataSet;
    }

CustomMarkerView.java

package xxx;  

import android.content.Context;
import android.widget.TextView;

import com.github.mikephil.charting.charts.LineChart;
import com.github.mikephil.charting.components.MarkerView;
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.highlight.Highlight;
import com.github.mikephil.charting.utils.MPPointF;

import xxx.R;

public class CustomMarkerView extends MarkerView {
    private TextView tv_content;
    private LineChart lineChart;

    /**
     * Constructor. Sets up the MarkerView with a custom layout resource.
     *
     * @param context
     * @param layoutResource the layout resource to use for the MarkerView
     */
    public CustomMarkerView(Context context, int layoutResource, LineChart lineChart) {
        super(context, layoutResource);
        tv_content = findViewById(R.id.tv_content);
        this.lineChart = lineChart;
    }

    @Override
    public void refreshContent(Entry e, Highlight highlight) {
        LineData lineData = lineChart.getLineData();  //得到已经绘制成型的折线图的数据
        LineDataSet set1 = (LineDataSet) lineData.getDataSetByIndex(0);  //获取第一条折线图Y轴数据
        LineDataSet set2 = (LineDataSet) lineData.getDataSetByIndex(1);  //获取第二条折线图Y轴数据

        int dataSetIndex = highlight.getDataSetIndex();  //获取点击的是哪条折线上的交叉点,0就是第一条,以此类推
        int index;
        if (dataSetIndex == 0) {
            index = set1.getEntryIndex(e);  //根据点击的该条折线上的点,获取当前Y轴数据对应的index值
        } else {
            index = set2.getEntryIndex(e);  //同上
        }
        //根据index值,分别获取当前Y轴上对应的两条折线的Y轴的值
        Entry entry1 = set1.getEntryForIndex(index);
        String week = "";
        switch (index) {
            case 0:
                week = "周一";
                break;
            case 1:
                week = "周二";
                break;
            case 2:
                week = "周三";
                break;
            case 3:
                week = "周四";
                break;
            case 4:
                week = "周五";
                break;
            case 5:
                week = "周六";
                break;
            case 6:
                week = "周日";
                break;
        }
        if (index < set2.getEntryCount()) {
            Entry entry2 = set2.getEntryForIndex(index);
            tv_content.setText(week + "\n\n上周:" + (int)entry1.getY() + "\n\n" + "本周:" + (int)entry2.getY());
        } else {
            tv_content.setText(week + "\n\n上周:" + (int)entry1.getY());
        }
        super.refreshContent(e, highlight);
    }

    @Override
    public MPPointF getOffset() {
        return new MPPointF(-(getWidth() / 2), -getHeight());
    }
}

content_marker_view.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content" android:layout_height="wrap_content"
    android:background="@drawable/shape_marker_view_background"
    android:alpha="0.8"
    android:padding="10dp">

    <TextView
        android:id="@+id/tv_content"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:textColor="@color/baseColor2"
        android:textSize="12dp"/>
</RelativeLayout>

shape_marker_view_background.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <corners android:radius="5dp"/>
    <solid android:color="@color/baseColor5"/>
</shape>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值