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项目实战(九)——自定义带文字分段堆积柱状图  

一丶先看效果图

MPAndroidChart项目实战(二)——双平滑曲线(双折线图)和MarkView实现_第1张图片                 MPAndroidChart项目实战(二)——双平滑曲线(双折线图)和MarkView实现_第2张图片

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();
    }

    /**
     * 

初始化chart

*/ 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); } /** *

初始化属性信息

*/ 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); } /** *

初始化Legend展示信息

* @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); } /** *

图例说明

* @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 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 {

    public LineChartEntity (LineChart lineChart, List []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 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);
        }

    }


    /**
     * 

填充曲线以下区域

* @param drawable 填充drawable * @param filledColor 填充颜色值 * @param fill true:填充 */ public void toggleFilled(Drawable []drawable, int []filledColor, boolean fill) { List 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(); } /** *

绘制曲线上点

* @param draw true:绘制 */ public void drawCircle ( boolean draw) { List 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 sets = ((LineChart)mChart).getData().getDataSets(); for (ILineDataSet iSet : sets) { LineDataSet set = (LineDataSet) iSet; set.setMode(mode); } mChart.invalidate(); } public void setEnableDashedLine (boolean enable) { List 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 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 fansMonthList, LineChart lineChart, int[] colors, Drawable[] drawables, final String unit, List values1, List values2, final String[] labels) {
        List[] 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

写在最后微信扫码提问

MPAndroidChart项目实战(二)——双平滑曲线(双折线图)和MarkView实现_第3张图片

你可能感兴趣的:(MPAndroidChart,MPChart双曲线,Android双折现,Android双平滑曲线,Android,Github,Android,开发心得)