MPAndroidChart项目实战(二)——双平滑曲线(双折线图)和MarkView实现

Demo补充中(UpDating):https://github.com/JinBoy23520/MPAndroidChartDemoByJin

本文出自:http://blog.csdn.net/dt235201314/article/details/54135182

MPAndroidChart常见设置属性(一)——应用层  
MPAndroidChart项目实战(一)——实现对比性柱状图  
MPAndroidChart项目实战(二)——双平滑曲线(双折线图)和MarkView实现  
MPAndroidChart项目实战(三)——饼状图实现和文字重合问题解决  
MPAndroidChart项目实战(四)——柱状图实现及X轴文字不显示问题和柱状图上显示文字  
MPAndroidChart X轴文字斜着显示  
MPAndroidChart项目实战(五)——组合图实现趋势图  
MPAndroidChart项目实战(六)——自定义1MPAndroidChart滑动冲突解决(搞不定产品设计师就只能搞自己)  
MPAndroidChart项目实战(七)——自定义横向柱状图  
MPAndroidChart项目实战(八)——自定义分段堆积柱状图  
MPAndroidChart项目实战(九)——自定义带文字分段堆积柱状图  

一丶先看效果图

                 

Gif图大小限制,效果不是很清晰,高清效果是特别帅的

二丶先说一下功能点

1.双折线图(平滑曲线),展现对比效果

2.X轴单位,默认显示在1(月)

3.Y轴单位(%)或者其他,但文字写上去总是有点丑,就没放在Y轴

4.MarkView这里的不同点在于,点击一个点显示相同X轴对比的数据

5.新版MPAndroidChart支持两条折现X长度不一样,就是有一条为null就只显示另一条,当长度不一同样可以显示,老版本(jar包版本)就不行。

6.解决MPAndroidChart在ViewPage+fragment里的滑动冲突

三丶看代码

MPAndroidChart库的导入与基本属性:(参考刘某人MPAndroidChart专栏),写得很详细(自己想写的但又落在别人后面,又少了增粉蹭浏览量的好机会)

MPAndroidChart常见设置属性(一)——应用层

Android图表库MPAndroidChart(十四)——在ListView种使用相同的图表

1.项目复用率很高,先得有个BaseChartEntry.Java

public abstract class BaseChartEntity<T extends Entry> {

    protected BarLineChartBase mChart;

    protected List<T>[] mEntries;
    protected String[] labels;
    protected int []mChartColors;
    protected float mTextSize;
    protected int mValueColor;
    protected BaseChartEntity(BarLineChartBase chart, List<T> []entries, String[] labels,
                              int []chartColor, int valueColor, float textSize) {
        this.mChart = chart;
        this.mEntries = entries;
        this.labels = labels;
        this.mValueColor = valueColor;
        this.mChartColors = chartColor;
//        this.mTextSize = textSize;
        this.mTextSize = 11f;
        initChart();
    }

    /**
     * <p>初始化chart</p>
     */
    protected void initChart() {
        initProperties();
        setChartData();
        initLegend(Legend.LegendForm.LINE, mTextSize, mValueColor);
        initXAxis(mValueColor, mTextSize);
        initLeftAxis(mValueColor, mTextSize);
    }


    private void initLeftAxis(int color, float textSize) {
        YAxis leftAxis = mChart.getAxisLeft();
        leftAxis.setTextColor(color);
        leftAxis.setTextSize(textSize);
        float yMax = mChart.getData().getYMax() == 0 ? 100f : mChart.getData().getYMax();
        leftAxis.setAxisMaximum(yMax + yMax * 0.007f);
//        leftAxis.setAxisMinimum(0f);
        leftAxis.setDrawGridLines(false);
        leftAxis.setGranularityEnabled(false);
        leftAxis.setDrawZeroLine(false);
        leftAxis.setLabelCount(6);
        leftAxis.setAxisLineWidth(1f);
        leftAxis.setAxisLineColor(mValueColor);

        mChart.getAxisRight().setEnabled(false);

    }

    private void initXAxis(int color, float textSize) {
        XAxis xAxis = mChart.getXAxis();
        xAxis.setTextSize(textSize);
        xAxis.setAxisMinimum(0);
        xAxis.setTextColor(color);
        xAxis.setDrawGridLines(false);
        xAxis.setDrawAxisLine(true);
        xAxis.setDrawLabels(true);
        xAxis.setAxisLineWidth(1f);
        xAxis.setLabelCount(8);
        xAxis.setDrawLimitLinesBehindData(true);
        xAxis.setAxisLineColor(mValueColor);
        xAxis.setCenterAxisLabels(false);
        xAxis.setAxisMinimum(mChart.getData().getXMin());
        xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
    }

    /**
     * <p>初始化属性信息</p>
     */
    private void initProperties() {
        mChart.setNoDataText("");
        // no description text
        mChart.getDescription().setEnabled(false);
        // enable touch gestures
        mChart.setTouchEnabled(true);
        mChart.setDragDecelerationFrictionCoef(0.9f);
        // enable scaling and dragging
        mChart.setDragEnabled(true);
        mChart.setScaleXEnabled(true);
        mChart.setPinchZoom(false);
        mChart.setVisibleXRangeMaximum(6);
        mChart.setScaleYEnabled(false);
        mChart.setDrawGridBackground(false);
        mChart.setHighlightPerDragEnabled(false);
        // if disabled, scaling can be done on x- and y-axis separately
        mChart.setPinchZoom(false);
    }

    /**
     * <p>初始化Legend展示信息</p>
     * @param form 样式
     * @param legendTextSize 文字大小
     * @param legendColor 颜色值
     */
    public void initLegend(Legend.LegendForm form, float legendTextSize, int legendColor) {
        // get the legend (only possible after setting data)
        Legend l = mChart.getLegend();
        // modify the legend ...
        l.setForm(form);
        l.setTextSize(legendTextSize);
        l.setTextColor(legendColor);
        //l.setYOffset(11f);
        updateLegendOrientation(Legend.LegendVerticalAlignment.BOTTOM, Legend.LegendHorizontalAlignment.RIGHT, Legend.LegendOrientation.HORIZONTAL);
    }

    /**
     * <p>图例说明</p>
     * @param vertical 垂直方向位置 默认底部
     * @param horizontal 水平方向位置 默认右边
     * @param orientation 显示方向 默认水平展示
     */

    public void updateLegendOrientation (Legend.LegendVerticalAlignment vertical, Legend.LegendHorizontalAlignment horizontal, Legend.LegendOrientation orientation) {
        Legend l = mChart.getLegend();
        l.setVerticalAlignment(vertical);
        l.setHorizontalAlignment(horizontal);
        l.setOrientation(orientation);
        l.setDrawInside(false);

    }

    /**
     * 图表value显示开关
     */
    public void toggleChartValue () {
        List<BaseDataSet> sets = mChart.getData().getDataSets();
        for (BaseDataSet iSet : sets) {
            iSet.setDrawValues(!iSet.isDrawValuesEnabled());
        }
        mChart.invalidate();
    }

    public void setMarkView (MarkerView markView) {
        markView.setChartView(mChart); // For bounds control
        mChart.setMarker(markView); // Set the marker to the chart
        mChart.invalidate();
    }

    /**
     * x/ylabel显示样式
     * @param xvalueFromatter x
     * @param leftValueFromatter y
     */
    public void setAxisFormatter(IAxisValueFormatter xvalueFromatter, IAxisValueFormatter leftValueFromatter) {
        mChart.getXAxis().setValueFormatter(xvalueFromatter);
        mChart.getAxisLeft().setValueFormatter(leftValueFromatter);
        mChart.invalidate();

    }

    protected abstract void setChartData();


    /**
     * value显示格式设置
     * @param valueFormatter IValueFormatter
     */
    public void setDataValueFormatter(IValueFormatter valueFormatter) {
        mChart.getData().setValueFormatter(valueFormatter);
    }
}
这里设置了一些简单属性和方法类似setMarkView等,方便统一使用。需要修改时重写方法修改就行。


2.下面这个类就厉害了,基本是根据设计图样式添加的一些属性方法(对应图表一的基本属性),同样修要修改时重写方法就可以哒

public class LineChartEntity extends BaseChartEntity<Entry> {

    public LineChartEntity (LineChart lineChart, List<Entry> []entries, String[] labels,
                             int []chartColor, int valueColor, float textSize) {
        super(lineChart, entries, labels, chartColor, valueColor, textSize);
    }


    @Override
    protected void initChart() {
        super.initChart();
        mChart.getAxisLeft().setDrawGridLines(true);
        mChart.getAxisLeft().enableGridDashedLine(10f, 15f, 0f);
        mChart.getAxisLeft().setGridLineWidth(0.5f);
        mChart.getAxisLeft().setGridColor(Color.parseColor("#f5f5f5"));
        mChart.getAxisLeft().setDrawZeroLine(false);
        mChart.getAxisRight().setDrawZeroLine(false);
        mChart.getAxisRight().setZeroLineWidth(0f);
        mChart.getAxisLeft().setZeroLineWidth(0f);
        mChart.getAxisLeft().setDrawAxisLine(false);
        mChart.getXAxis().setDrawAxisLine(false);
//        mChart.setScaleMinima(1.38f, 1f);
//        mChart.getXAxis().setDrawGridLines(true);
//        mChart.getXAxis().enableGridDashedLine(20f, 20f, 0f);
    }

    @Override
    protected void setChartData() {
        LineDataSet []lineDataSet = new LineDataSet[mEntries.length];
            if (mChart.getData() != null && mChart.getData().getDataSetCount() == mEntries.length) {
                for(int index = 0, len = mEntries.length; index < len; index ++) {
                    List<Entry> list = mEntries[index];
                    lineDataSet[index] = (LineDataSet) mChart.getData().getDataSetByIndex(index);
                    lineDataSet[index].setValues(list);
                }
                mChart.getData().notifyDataChanged();
                mChart.notifyDataSetChanged();
            }  else {
                for (int index = 0, len = mEntries.length; index < len; index ++) {
                    lineDataSet[index] = new LineDataSet(mEntries[index], labels[index]);
                    lineDataSet[index].setAxisDependency(YAxis.AxisDependency.LEFT);
                    lineDataSet[index].setColor(mChartColors[index]);
                    lineDataSet[index].setLineWidth(1.5f);
                    lineDataSet[index].setCircleRadius(3.5f);
                    lineDataSet[index].setCircleColor(mChartColors[index]);
                    lineDataSet[index].setFillAlpha(25);
//                    lineDataSet[index].enableDashedLine(10f, 15f, 0f);
//                    lineDataSet[index].enableDashedHighlightLine(10f, 15f, 0f);
                    lineDataSet[index].setDrawCircleHole(false);
                    lineDataSet[index].setValueTextColor(mChartColors[index]);
//                    lineDataSet[index].setFillColor(ColorTemplate.colorWithAlpha(Color.YELLOW, 200));

                }
                // create a data object with the datasets
                LineData data = new LineData(lineDataSet);
                data.setValueTextSize(mTextSize);

                // set data
                mChart.setData(data);
                mChart.animateX(2000, Easing.EasingOption.EaseInOutQuad);
        }

    }


    /**
     * <p>填充曲线以下区域</p>
     * @param drawable 填充drawable
     * @param filledColor 填充颜色值
     * @param fill true:填充
     */
    public void toggleFilled(Drawable []drawable, int []filledColor, boolean fill) {
        List<ILineDataSet> sets = ((LineChart)mChart).getData().getDataSets();

        for (int index = 0, len = sets.size(); index < len; index ++ ) {
            LineDataSet set = (LineDataSet) sets.get(index);
            if (drawable != null) {
                set.setFillDrawable(drawable[index]);
            } else if (filledColor != null){
                set.setFillColor(filledColor[index]);
            }
            set.setDrawFilled(fill);
        }
        mChart.invalidate();
    }

    /**
     * <p>绘制曲线上点</p>
     * @param draw true:绘制
     */
    public void drawCircle ( boolean draw) {
        List<ILineDataSet> sets = ((LineChart)mChart).getData().getDataSets();
        for (ILineDataSet iSet : sets) {
            LineDataSet set = (LineDataSet) iSet;
            set.setDrawCircles(draw);
        }
        mChart.invalidate();
    }

    /**
     * 设置图表颜色值
     * @param mode LineDataSet.Mode
     */
    public void setLineMode (LineDataSet.Mode mode) {
        List<ILineDataSet> sets = ((LineChart)mChart).getData().getDataSets();
        for (ILineDataSet iSet : sets) {
            LineDataSet set = (LineDataSet) iSet;
            set.setMode(mode);
        }
        mChart.invalidate();
    }

    public void setEnableDashedLine (boolean enable) {
        List<ILineDataSet> sets = ((LineChart)mChart).getData().getDataSets();
        for (ILineDataSet iSet : sets) {
            LineDataSet set = (LineDataSet) iSet;
            if (enable) {
                set.disableDashedLine();
            } else {
//                set.setFormLineWidth(1f);
//                set.setFormLineDashEffect(new DashPathEffect(new float[]{10f, 5f}, 0f));
//                set.setFormSize(15.f);
                set.enableDashedLine(10f, 5f, 0f);
                set.enableDashedHighlightLine(10f, 5f, 0f);
            }
        }
        mChart.invalidate();

    }

    /**设置x缩放的最小最大值*/
    public void setMinMaxScaleX(float minScaleX, float maxScaleX) {
        mChart.getViewPortHandler().setMinMaxScaleX(minScaleX, maxScaleX);
    }
}
每个方法上都有所标注,功能方法填充背景啊,绘制动画啊,折现类型啊,缩放最大值最小值啊等

说一下这个最大值最小值,当图标控件宽设为martch,那么1就是屏幕宽度,1.5就是1.5个屏幕宽度

当都设为同一个值时是就是不允许缩放,大于1可滑动,都等于1就是不可缩放不可滑动


3.V层应用重要方法

public void updateLineData (LineChart mChart ) {
    List<ILineDataSet> sets = mChart.getData().getDataSets();
    for (ILineDataSet iSet : sets) {
        LineDataSet set = (LineDataSet) iSet;
        set.setFillAlpha(255);
        set.setDrawCircleHole(true);
    }
    mChart.getAxisLeft().setDrawGridLines(true);
    mChart.getAxisLeft().enableGridDashedLine(10f, 0f, 0f);
    mChart.getAxisLeft().setGridLineWidth(0.5f);
    mChart.getAxisLeft().setGridColor(Color.parseColor("#f5f5f5"));
    mChart.getXAxis().setDrawGridLines(true);
    mChart.getXAxis().enableGridDashedLine(10f, 0f, 0f);
    mChart.getXAxis().setGridLineWidth(0.5f);
    mChart.getXAxis().setGridColor(Color.parseColor("#f5f5f5"));
    mChart.invalidate();
}
这个方法就是重写折线图样式,相对于GIF图二,这里将圆点改为空心,填充背景透明度改为255最大就是没有

然后就是绘制X和Y轴网格,enableGridLines属性本来是绘制虚线属性,当后面两位都为0时就成了实线


好现在上最重要的方法(传入双折线图数值,线色,背景填充,X轴,Y轴样式,MarkView展现)

 private void updateLinehart(final List<FansMonthListEntity> fansMonthList, LineChart lineChart, int[] colors, Drawable[] drawables, final String unit, List<Entry> values1, List<Entry> values2, final String[] labels) {
        List<Entry>[] entries = new ArrayList[2];
        entries[0] = values1;
        entries[1] = values2;
        LineChartEntity lineChartEntity = new LineChartEntity(lineChart, entries, labels, colors, Color.parseColor("#999999"), 12f);
        lineChartEntity.drawCircle(true);
        lineChart.setScaleMinima(1.0f, 1.0f);
//        toggleFilled(lineChartEntity, drawables, colors);
        lineChartEntity.setLineMode(LineDataSet.Mode.LINEAR);
        lineChartEntity.initLegend(Legend.LegendForm.CIRCLE, 12f, Color.parseColor("#999999"));
        lineChartEntity.updateLegendOrientation(Legend.LegendVerticalAlignment.TOP, Legend.LegendHorizontalAlignment.RIGHT, Legend.LegendOrientation.HORIZONTAL);
        lineChartEntity.setAxisFormatter(
                new IAxisValueFormatter() {
                    @Override
                    public String getFormattedValue(float value, AxisBase axis) {
                        if (value == 1.0f) {
                            return mFormat.format(value) + mContext.getResources().getString(R.string.line_x_unit_month);
                        }
                        String monthStr = mFormat.format(value);
                        if (monthStr.contains(".")) {
                            return "";
                        } else {
                            return monthStr;
                        }
//                        return mMonthFormat.format(value);
                    }
                },
                new IAxisValueFormatter() {
                    @Override
                    public String getFormattedValue(float value, AxisBase axis) {
                        return mFormat.format(value) + unit;
                    }
                });

        lineChartEntity.setDataValueFormatter(new IValueFormatter() {
            @Override
            public String getFormattedValue(float value, Entry entry, int dataSetIndex, ViewPortHandler viewPortHandler) {
                return mFormat.format(value) + unit;
            }
        });

        final NewMarkerView markerView = new NewMarkerView(mContext, R.layout.custom_marker_view_layout);
        markerView.setCallBack(new NewMarkerView.CallBack() {
            @Override
            public void onCallBack(float x, String value) {
                int index = (int) (x);
                if (index < 0) {
                    return;
                }
                if (index > fansMonthList.size()) {
                    return;
                }
                String textTemp = "";
                String monthUnit = mContext.getResources().getString(R.string.home_text_month);
                if (index <= fansMonthList.size()) {

                    textTemp += labels[0] + "(" + index + monthUnit +  ")" + ":" + mFormat.format(Float.parseFloat(fansMonthList.get(index - 1).getFansNum())) + unit;
                    textTemp += "\n";
                    textTemp += labels[1] + "(" + index + monthUnit +  ")" +  ":" + mFormat.format(Float.parseFloat(fansMonthList.get(index - 1).getFansRealNum())) + unit;
                }

                markerView.getTvContent().setText(textTemp);
            }
        });
        lineChartEntity.setMarkView(markerView);
        lineChart.getData().setDrawValues(false);
    }

好,重要的代码都展现在这里。


不好意思贴掉了一个类NewMarkerView详情见博客:

MPAndroidChart项目实战——MarkerView显示问题解决


最后谈一谈开发时遇到的一些bug

1.lineChart滑动冲突

参考:MPAndroidChart在ViewPager+Fragment滑动冲突解决

2.当数据都为0时,X轴成一条直线,有时还出现负数,Y轴被压缩,文字重复显示,特别丑

mChart.getAxisLeft().setAxisMinimum(0);
mChart.getAxisLeft().setAxisMaximum((float) (mChart.getData().getYMax() *1.1 + 20));
解决方法设置Y轴最小值为0,最大值为获得的最大值得1.1倍加20

这样既不会出现负数Y轴数值也不会压缩在一起

3.日月图表切换时,月表无辜变特别长,日X轴30~31个点,月12个点

解决方法:日月切换时重新设定缩放倍数

linechart.getViewPortHandler().setMinMaxScaleX(2,2);
4.markview,这个是真难,代码如上,但是大神帮忙解决的


总结:

MPAndroidChart是很好的开源库,新老版本改变差别较大,各有利弊。但jar包版(老版本)和新版本能共存,可解决很多问题

当开源库不能达到需求时,就要修改开源库,这个对于目前的我太难了,而同事能做到,这方便要加强,对开源源码的解读要加强

文章写到这里希望对大家能有帮助,不懂的地方直接评论问,另外,文章画了不少时间希望能成为我的第一篇技术文章,希望大家支持


五丶跪求关注下载源码,200粉小目标
欢迎关注我的博客及微信公众号,后面会给大家带来更多相关MPAndroidChart无法解决的仿MPAndroidChart图标自定义控件
源码下载记得顺便Star哦~
下载链接:https://github.com/JinBoy23520/MPAndroidChartDemoByJin

写在最后微信扫码提问


已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页