Android 图表开源框架之MPAndroidChart LineChart折线图(三)

Android 图表开源框架之MPAndroidChart LineChart折线图(一)

Android 图表开源框架之MPAndroidChart LineChart折线图(二)

Android 图表开源框架之MPAndroidChart LineChart之常用自定义设置功能

源码下载地址:MPAndroidChart3_0_1.zip https://mp.csdn.net/console/upDetailed

Android 图表开源框架之MPAndroidChart LineChart折线图,v3.0.1版本,MPAndroidChart是一款基于Android的开源图表库,MPAndroidChart不仅可以在Android设备上绘制各种统计图表,而且可以对图表进行拖动和缩放操作,应用起来非常灵活。MPAndroidChart显得更为轻巧和简单,拥有常用的图表类型:线型图、饼图、柱状图和散点图。

一.效果图:

二.快速实现:

1
implementation 'com.github.PhilJay:MPAndroidChart:v3.0.1'

1.主函数代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.Typeface;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.text.format.DateFormat;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;

import com.example.m1571.mympandroidchart.utils.CustomXValueFormatter;
import com.example.m1571.mympandroidchart.utils.MyMarkerView;
import com.example.m1571.mympandroidchart.utils.MyMarkersView;
import com.github.mikephil.charting.animation.Easing;
import com.github.mikephil.charting.charts.LineChart;
import com.github.mikephil.charting.charts.PieChart;
import com.github.mikephil.charting.components.AxisBase;
import com.github.mikephil.charting.components.Description;
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.github.mikephil.charting.data.PieData;
import com.github.mikephil.charting.data.PieDataSet;
import com.github.mikephil.charting.data.PieEntry;
import com.github.mikephil.charting.formatter.IAxisValueFormatter;
import com.github.mikephil.charting.formatter.PercentFormatter;
import com.github.mikephil.charting.highlight.Highlight;
import com.github.mikephil.charting.interfaces.datasets.ILineDataSet;
import com.github.mikephil.charting.listener.OnChartValueSelectedListener;
import com.github.mikephil.charting.utils.ColorTemplate;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 *
 * 图表开源框架
 * https://blog.csdn.net/qq_43332570/article/details/103180779
 *
 *https://blog.csdn.net/qq_26787115/article/details/53611373
 *
 *
 * https://www.jb51.net/article/142778.htm
 * https://www.jb51.net/article/141344.htm
 * https://www.jb51.net/article/96508.htm
 * <p>
 * https://github.com/hdodenhof/CircleImageView
 */
public class ChartActivity extends AppCompatActivity {
    ArrayList<PieEntry> pieEntryList = new ArrayList();//数据列表
    ArrayList<Integer> colors = new ArrayList();//颜色列表
    private LineChart lineChart;
    float datas[] = {14f,15f,16f,17f,16f,16f};
    float datas2[] = {17f,16f,15f,14f,17f,14f};
    //在MPAndroidChart一般都是通过List<Entry>对象来装数据的
    final List<Entry> entries = new ArrayList<Entry>();
    final List<Entry> entries2 = new ArrayList<Entry>();
    final List<String> yRightList = new ArrayList<String>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_chart);
        lineChart = (LineChart) findViewById(R.id.lineChart);
        List<Integer> mylist = new ArrayList<>();
//        for (int i = 0; i < 10; i++) {
//            mylist.add(i);
//        }
        mylist.add(1);
        mylist.add(8);
        mylist.add(3);
        mylist.add(7);
        mylist.add(2);
        mylist.add(8);
        mylist.add(5);
        mylist.add(0);
        mylist.add(1);
        mylist.add(6);
        setData(mylist);
        //解决滑动冲突
//        lineChart.setOnTouchListener(new View.OnTouchListener()
//        {
//            @Override
//            public boolean onTouch(View v, MotionEvent event)
//            {
//                switch (event.getAction())
//                {
//                    case MotionEvent.ACTION_DOWN:
//                    {
//                        scrollview.requestDisallowInterceptTouchEvent(true);
//                        break;
//                    }
//                    case MotionEvent.ACTION_CANCEL:
//                    case MotionEvent.ACTION_UP:
//                    {
//                        scrollview.requestDisallowInterceptTouchEvent(false);
//                        break;
//                    }
//                }
//                return false;
//            }
//        });
    }
/**
 * 初始化曲线图表
 *
 * @param list 数据集
 */
    public void setData(final List<Integer> list){

        //显示边界
        lineChart.setDrawBorders(false);
        //设置数据
        List<Entry> entries = new ArrayList<>();
        for (int i = 0; i < list.size(); i++)
        {
            entries.add(new Entry(i, (float) list.get(i)));
        }
        //一个LineDataSet就是一条线
        LineDataSet lineDataSet = new LineDataSet(entries, "sgf");
        //线颜色
        lineDataSet.setColor(Color.parseColor("#F15A4A"));
        //线宽度
        lineDataSet.setLineWidth(1.6f);
        //不显示圆点
        lineDataSet.setDrawCircles(false);
        //线条平滑
        lineDataSet.setMode(LineDataSet.Mode.HORIZONTAL_BEZIER);

        lineDataSet.setDrawFilled(true);
        lineDataSet.setFillAlpha(50);
        lineDataSet.setFillColor(Color.RED);
//        dataSet.setFillColor(R.drawable.gradient_chart_bg2);
        int[] colors = { getResources().getColor(R.color.colorAccent),
                getResources().getColor(android.R.color.white) };
//        dataSet.setFillColor(getResources().getColor(R.drawable.gradient_chart_bg2));
        //设置曲线下方渐变的阴影
        lineDataSet.setDrawFilled(true);
        lineDataSet.setFillDrawable(getResources().getDrawable(R.drawable.line_gradient_bg_shape));
        lineDataSet.setLineWidth(1.75f); // 线宽
        lineDataSet.setCircleSize(5f);// 显示的圆形大小
        lineDataSet.setDrawCircles(true);// 是否有圆点
//      lineDataSet.setDrawCircleHole(true);// 设置数据点是空心还是实心,默认空心
        lineDataSet.setDrawValues(true);//设置是否显示点的坐标值
        // 设置平滑曲线模式
//          lineDataSet.setMode(LineDataSet.Mode.STEPPED);//梯形
//          lineDataSet.setMode(LineDataSet.Mode.CUBIC_BEZIER);//曲线模式
          lineDataSet.setMode(LineDataSet.Mode.LINEAR);//折线
//          lineDataSet.setMode(LineDataSet.Mode.HORIZONTAL_BEZIER);//曲线模式

        //设置折线图填充
//        lineDataSet.setDrawFilled(true);
        LineData data = new LineData(lineDataSet);
        //无数据时显示的文字
        lineChart.setNoDataText("暂无数据");
        //折线图不显示数值
        data.setDrawValues(false);
        //得到X轴
        XAxis xAxis = lineChart.getXAxis();
        //设置X轴的位置(默认在上方)
        xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
        //设置X轴坐标之间的最小间隔
        xAxis.setGranularity(1f);
        //设置X轴的刻度数量,第二个参数为true,将会画出明确数量(带有小数点),但是可能值导致不均匀,默认(6,false)
        //xAxis.setLabelCount(list.size() / 6, false);
xAxis.setLabelCount(list.size(), false);
        //设置X轴的值(最小值、最大值、然后会根据设置的刻度数量自动分配刻度显示)
        xAxis.setAxisMinimum(0f);
        xAxis.setAxisMaximum((float) list.size());
        //不显示网格线
        xAxis.setDrawGridLines(false);
        // 标签倾斜
//        xAxis.setLabelRotationAngle(45);
        //设置X轴值为字符串 可在这里自定义要显示的单位
        xAxis.setValueFormatter(new IAxisValueFormatter()
        {
            @Override
            public String getFormattedValue(float value, AxisBase axis)
            {
                int IValue = (int) value;
                CharSequence format = DateFormat.format("MM/dd",
                        System.currentTimeMillis()-(long)(list.size()-IValue)*24*60*60*1000);
                return format.toString();
            }
        });

        Legend mLegend = lineChart.getLegend(); //设置标示,就是那个一组y的value的
//        mLegend.setForm(Legend.LegendForm.DEFAULT); //默认圆形样式
//        mLegend.setForm(Legend.LegendForm.SQUARE); //方形样式
//        mLegend.setForm(Legend.LegendForm.CIRCLE); //圆形样式
        mLegend.setForm(Legend.LegendForm.LINE); //横线的样式
        mLegend.setFormSize(6f); //字体
//        mLegend.setXEntrySpace(6f); //设置在水平轴上 legend-entries 的间隙
        mLegend.setYEntrySpace(6f); //设置在垂直轴上 legend-entries 的间隙
        mLegend.setFormToTextSpace(6f); //设置 legend-form 和 legend-label 之间的空间
        mLegend.setWordWrapEnabled(true); //设置 Legend 是否自动换行? 目前仅支持BelowChartLeft,BelowChartRight
        mLegend.setTextColor(Color.RED); //设置字体颜色
        mLegend.setPosition(Legend.LegendPosition.BELOW_CHART_LEFT); //设置显示下位置在左侧
//        mLegend.setPosition(Legend.LegendPosition.BELOW_CHART_RIGHT); //设置显示下位置在右侧
//        mLegend.setPosition(Legend.LegendPosition.BELOW_CHART_CENTER); //设置显示下位置在中间
//        mLegend.setPosition(Legend.LegendPosition.RIGHT_OF_CHART); //设置显示图平行的右侧
//        mLegend.setPosition(Legend.LegendPosition.LEFT_OF_CHART); //设置显示图平行的左侧
//        mLegend.setPosition(Legend.LegendPosition.RIGHT_OF_CHART_CENTER); //设置显示图平行的右侧据居中
//        mLegend.setPosition(Legend.LegendPosition.LEFT_OF_CHART_INSIDE); //
//        mLegend.setPosition(Legend.LegendPosition.PIECHART_CENTER); //PieChart独有,折线图会显示在中间
//        mLegend.setPosition(Legend.LegendPosition.LEFT_OF_CHART_CENTER); //设置显示图平行的左侧据居中
        mLegend.setTypeface(Typeface.DEFAULT); //设置图例标签的字体
//        mLegend.setForm(Legend.LegendForm.NONE);//不绘制图形
//        mLegend.setForm(Legend.LegendForm.EMPTY);;//不绘制图形保留空间
//        mLegend.setForm(Legend.LegendForm.LINE); // 线
//        mLegend.setFormSize(14f); // 图形大小
//        mLegend.setFormLineWidth(9f);  // 图形线宽
        //隐藏Lengend
        mLegend.setEnabled(true);
        // set custom labels and colors
//        mLegend.setCustom(ColorTemplate.VORDIPLOM_COLORS,
//                new String[] { "Set1", "Set2", "Set3", "Set4", "Set5" });

        LimitLine limitLineL = new LimitLine(8f, "临界点");//临界点
        limitLineL.setLineColor(Color.RED);
        limitLineL.setLineWidth(1.5f);
        limitLineL.setTextSize(10f);
        limitLineL.setTextColor(Color.RED);
        limitLineL.setLabelPosition(LimitLine.LimitLabelPosition.RIGHT_TOP);//标签位置
        limitLineL.enableDashedLine(5f,8f,0);  //设置虚线
        lineChart.getAxisLeft().addLimitLine(limitLineL);

        //设置均值
        LimitLine ll2 = new LimitLine(5, "均值");
        ll2.setLabel("均值");
        ll2.setTextColor(Color.parseColor("#5dbcfe"));
        ll2.setLineWidth(1f);
        ll2.setEnabled(true);
        ll2.setLineColor(Color.parseColor("#5dbcfe"));
        ll2.enableDashedLine(5f, 10f, 0f);//三个参数,第一个线宽长度,第二个线段之间宽度,第三个一般为0,是个补偿
        ll2.setLabelPosition(LimitLine.LimitLabelPosition.RIGHT_BOTTOM);//标签位置
        ll2.setTextSize(10f);
        lineChart.getAxisLeft().addLimitLine(ll2);

        //得到Y轴
        YAxis yAxis = lineChart.getAxisLeft();
        YAxis rightYAxis = lineChart.getAxisRight();
        //设置Y轴是否显示
        rightYAxis.setEnabled(false); //右侧Y轴不显示
        //设置y轴坐标之间的最小间隔
        //不显示网格线
        yAxis.setDrawGridLines(false);
        //设置Y轴坐标之间的最小间隔
        yAxis.setGranularity(1);
        //设置y轴的刻度数量
        //+2:最大值n就有n+1个刻度,在加上y轴多一个单位长度,为了好看,so+2
        yAxis.setLabelCount(Collections.max(list) + 2, false);
        //设置从Y轴值
        yAxis.setAxisMinimum(0f);
        //+1:y轴多一个单位长度,为了好看
        yAxis.setAxisMaximum(Collections.max(list) + 1);

        //y轴,可在这里设置自定义的单位
        yAxis.setValueFormatter(new IAxisValueFormatter()
        {
            @Override
            public String getFormattedValue(float value, AxisBase axis)
            {
                int IValue = (int) value;
                return String.valueOf(IValue)+"辆";
            }
        });
        //图例:得到Lengend
//        Legend legend = lineChart.getLegend();
        //隐藏Lengend
//        legend.setEnabled(true);
        //隐藏描述
        Description description = new Description();
        description.setEnabled(true);
        lineChart.setDescription(description);
        lineChart.getDescription().setText("hi");
        //折线图点的标记
        MyMarkersView mv = new MyMarkersView(this);
        lineChart.setMarker(mv);
        //设置数据
        lineChart.setData(data);
        //设置动画效果
        lineChart.animateY(2000, Easing.EasingOption.Linear);
        lineChart.animateX(2000, Easing.EasingOption.Linear);

        //图标刷新
        lineChart.invalidate();
    }
}

2.渐变色背景:

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <gradient
        android:angle="-90"
        android:endColor="#FEFFFF"
        android:startColor="#D9F3FF"></gradient>
</shape>

3.主函数布局:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?xml version="1.0" encoding="utf-8"?>
<ScrollView 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:background="#ccc"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">


        <com.github.mikephil.charting.charts.LineChart
            android:id="@+id/lineChart"
            android:layout_width="match_parent"
            android:layout_marginLeft="10dp"
            android:layout_marginRight="10dp"
            android:layout_marginBottom="10dp"
            android:layout_height="220dp"
            android:layout_centerInParent="true"/>
    </LinearLayout>
</ScrollView>

4.设置自定义标记提示框

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
import android.content.Context;
import android.text.format.DateFormat;
import android.widget.TextView;

import com.example.m1571.mympandroidchart.R;
import com.github.mikephil.charting.components.MarkerView;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.highlight.Highlight;
import com.github.mikephil.charting.utils.MPPointF;

import java.text.DecimalFormat;

public class MyMarkersView extends MarkerView
    {

        private TextView tvContent;
        private DecimalFormat format = new DecimalFormat("##0");

        public MyMarkersView(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(e.getX())+"\n"+format.format(e.getY())+"辆");
            super.refreshContent(e, highlight);
        }

        //标记相对于折线图的偏移量
        @Override
        public MPPointF getOffset() {
            return new MPPointF(-(getWidth() / 2), -getHeight());
        }

        //时间格式化(显示今日往前30天的每一天日期)
        public String  format(float x)
        {

int IValue = (int) x;
            CharSequence format = DateFormat.format("MM/dd",
                    System.currentTimeMillis()-(long)(list.size()-IValue)*24*60*60*1000);
           // CharSequence format = DateFormat.format("MM月dd日",
                   // System.currentTimeMillis()-(long) (30-(int)x)*24*60*60*1000);
            return format.toString();
        }

}

5.提示框布局:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:background="@drawable/bg_shape_c"
        android:layout_width="match_parent"
        android:paddingLeft="10dp"
        android:paddingRight="10dp"
        android:paddingTop="6dp"
        android:paddingBottom="6dp"
        android:layout_height="wrap_content">
        <TextView
            android:id="@+id/tvContent"
            android:text="KING"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    </LinearLayout>

</LinearLayout>

6.设置可以左右滑动的折线图效果:

1
2
3
4
5
6
7
8
9
//xAxis.setLabelCount(list.size() / 6, false);//注意请注释掉这一句代码
lineChart.setVisibleXRange(0, 6);   //x轴可显示的坐标范围
        lineChart.setDrawGridBackground(false); //表格颜色
        lineChart.setGridBackgroundColor(Color.GRAY & 0x70FFFFFF); //表格的颜色,设置一个透明度
        lineChart.setTouchEnabled(true); //可点击
        lineChart.setDragEnabled(true);  //可拖拽
        lineChart.setScaleEnabled(false);  //可缩放
        lineChart.setPinchZoom(false);
//        lineChart.setBackgroundColor(Color.WHITE); //设置背景颜色

7.设置折线中圆点对应的颜色(设置多种颜色值)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//根据数值大小区间来设置圆点对应的颜色
    //在方法中判断数值的大小和对应设置的颜色
    private static List<Integer> getLineColors(List<Entry> yValues,
                                               int normalColor, int exceColor, int exceQcColor) {
        List<Integer> list = new ArrayList<>();
//      float maxSD = (float) (targetValue + sdValue * sdMultiple);
//      float minSD = (float) (targetValue - sdValue * sdMultiple);
        float maxSD = 3;
        float minSD = 0;
        for (int i = 0; i < yValues.size(); i++) {
            Entry entry = yValues.get(i);
//            if (errIndexs.contains(i)) {  //限值异常质控不用和sd比较确定显示什么颜色
//                list.add(exceQcColor);
//                continue;
//            }
//          if (entry.getVal() >= maxSD || entry.getVal() < minSD) {
            //此处的entry.getVal()(2.1.6版本)等于entry.getY()(3.0.1版本)
            if (entry.getY() >= 6) {
                list.add(exceColor);
            } else if(entry.getY() == 5){
                list.add(normalColor);
            } else if(entry.getY() < 5){
//                list.add(exceQcColor);
            }
        }
        return list;
    }
1
2
3
4
 //设置折线圆点多种颜色值
        List<Integer> lineColors = getLineColors(entries, Color.RED, Color.YELLOW,
                Color.BLUE);
        lineDataSet.setCircleColors(lineColors);// 圆形的颜色

8.设置显示折线图圆点的数值,可以自定义单位:

1
2
//设置圆点显示内容替换原来的%为元
        lineDataSet.setValueFormatter(new TestDefaultValueFormatter());
1
2
3
4
5
6
7
8
9
10
11
12
13
 //1.在PieChartUtil 中创建内部类
    private class TestDefaultValueFormatter implements IValueFormatter {
        private DecimalFormat mFormat;

        public TestDefaultValueFormatter(){
            mFormat = new DecimalFormat("###");//十进制格式
        }

        @Override
        public String getFormattedValue(float value, Entry entry, int dataSetIndex, ViewPortHandler viewPortHandler) {
            return mFormat.format(value)+"辆";
        }
    }
1
lineDataSet.setDrawValues(true);//设置是否显示点的坐标值