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

来源:互联网 发布:网络控制器无法安装 编辑:程序博客网 时间:2024/06/05 10:54

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

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

一丶先看效果图

                 

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

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


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


9 0
原创粉丝点击