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

栏目: 编程工具 · 发布时间: 7年前

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

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

一丶先看效果图

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

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包版(老版本)和新版本能共存,可解决很多问题

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

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


以上所述就是小编给大家介绍的《MPAndroidChart项目实战(二)——双平滑曲线(双折线图)和MarkView实现》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Python for Data Analysis

Python for Data Analysis

Wes McKinney / O'Reilly Media / 2012-11-1 / USD 39.99

Finding great data analysts is difficult. Despite the explosive growth of data in industries ranging from manufacturing and retail to high technology, finance, and healthcare, learning and accessing d......一起来看看 《Python for Data Analysis》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具