美文网首页Android开发Android开发经验谈
MPAndroidChart部分自定义效果及问题

MPAndroidChart部分自定义效果及问题

作者: 一克拉泪 | 来源:发表于2018-07-27 15:00 被阅读21次

    由于项目中有表格统计,所以研究了MPAndroidChart这个库,这算是比较全的一个图表类库,再次感谢作者,膜拜。

    关于基础设置的部分网上资料也比较多,所以我主要讲的是自己遇到的需求及问题,不过前期对API也熟悉了一番,不知道的也可以留言,嘿嘿嘿。

    下面进去正题,先来看需求:

    需求一:

    柱状图有渐变色,如下:在网上找资料,查源代码半天,并没有可以设置的API,心死了一半,这不是难为我这样的小白么,呜呜呜。

    image

    功夫不负有心人,经过一番探索,在网上找到了个类似需求的,帮我顺利找到了修改源码的地方,在此感谢。接下来就是简单的自定义了,加油吧少年,哈哈。步骤如下:

    1 . 自定义两个类分别继承BarChart和BarChartRenderer

    public class MyBarChartRender extends BarChartRenderer {
    
        private RectF mBarShadowRectBuffer = new RectF();
    
        public MyBarChartRender(BarDataProvider chart, ChartAnimator animator,
                                ViewPortHandler viewPortHandler) {
            super(chart, animator, viewPortHandler);
            this.mChart = chart;
    
            mHighlightPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            mHighlightPaint.setStyle(Paint.Style.FILL);
            mHighlightPaint.setColor(Color.rgb(0, 0, 0));
            // set alpha after color
            mHighlightPaint.setAlpha(120);
    
            mShadowPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            mShadowPaint.setStyle(Paint.Style.FILL);
    
            mBarBorderPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            mBarBorderPaint.setStyle(Paint.Style.STROKE);
        }
    
        protected void drawDataSet(Canvas c, IBarDataSet dataSet, int index) {
    
            Transformer trans = mChart.getTransformer(dataSet.getAxisDependency());
    
            mBarBorderPaint.setColor(dataSet.getBarBorderColor());
            mBarBorderPaint.setStrokeWidth(Utils.convertDpToPixel(dataSet.getBarBorderWidth()));
    
            final boolean drawBorder = dataSet.getBarBorderWidth() > 0.f;
    
            float phaseX = mAnimator.getPhaseX();
            float phaseY = mAnimator.getPhaseY();
    
            // draw the bar shadow before the values
            if (mChart.isDrawBarShadowEnabled()) {
                mShadowPaint.setColor(dataSet.getBarShadowColor());
    
                BarData barData = mChart.getBarData();
    
                final float barWidth = barData.getBarWidth();
                final float barWidthHalf = barWidth / 2.0f;
                float x;
    
                for (int i = 0, count = Math.min((int)(Math.ceil((float)(dataSet.getEntryCount()) * phaseX)), dataSet.getEntryCount());
                     i < count;
                     i++) {
    
                    BarEntry e = dataSet.getEntryForIndex(i);
    
                    x = e.getX();
    
                    mBarShadowRectBuffer.left = x - barWidthHalf;
                    mBarShadowRectBuffer.right = x + barWidthHalf;
    
                    trans.rectValueToPixel(mBarShadowRectBuffer);
    
                    if (!mViewPortHandler.isInBoundsLeft(mBarShadowRectBuffer.right))
                        continue;
    
                    if (!mViewPortHandler.isInBoundsRight(mBarShadowRectBuffer.left))
                        break;
    
                    mBarShadowRectBuffer.top = mViewPortHandler.contentTop();
                    mBarShadowRectBuffer.bottom = mViewPortHandler.contentBottom();
    
                    c.drawRect(mBarShadowRectBuffer, mShadowPaint);
                }
            }
    
            // initialize the buffer
            BarBuffer buffer = mBarBuffers[index];
            buffer.setPhases(phaseX, phaseY);
            buffer.setDataSet(index);
            buffer.setInverted(mChart.isInverted(dataSet.getAxisDependency()));
            buffer.setBarWidth(mChart.getBarData().getBarWidth());
    
            buffer.feed(dataSet);
    
            trans.pointValuesToPixel(buffer.buffer);
    
            final boolean isSingleColor = dataSet.getColors().size() == 1;
    
            if (isSingleColor) {
                //mRenderPaint.setColor(dataSet.getColor());
            }
    
            for (int j = 0; j < buffer.size(); j += 4) {
                if (!mViewPortHandler.isInBoundsLeft(buffer.buffer[j + 2]))
                    continue;
    
                if (!mViewPortHandler.isInBoundsRight(buffer.buffer[j]))
                    break;
    
    //以下是主要代码,设置渐变柱状图,当柱状图设置为一种颜色时并不起作用,所以可以手动设置多种颜 色,而显示仍是以下面设置的渐变阴影色为主
                if (!isSingleColor) {
                    //float xValue = dataSet.getEntryForIndex(j/4).getX();
                    Shader shader = new LinearGradient(0, buffer.buffer[j+1], 0, buffer.buffer[j+3], Color.parseColor("#7dc7fc"),
                            Color.parseColor("#79a9fd"), Shader.TileMode.CLAMP);
                    mRenderPaint.setShader(shader);
                   //mRenderPaint.setColor(dataSet.getColor(j / 4));
                }
                c.drawRect(buffer.buffer[j], buffer.buffer[j + 1], buffer.buffer[j + 2],
                        buffer.buffer[j + 3], mRenderPaint);
            }
        }
    
    }
    
    
    public class MyBarChart extends BarChart {
    
        public MyBarChart(Context context) {
            super(context);
        }
    
        public MyBarChart(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        public MyBarChart(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
        }
    
        @Override
        protected void init() {
            super.init();
    
            mRenderer = new MyBarChartRender(this, mAnimator, mViewPortHandler);
        }
    
        PointF downPoint = new PointF();
    
        //为解决和viewpager滑动冲突,将viewpager滑动范围缩小
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    downPoint.x = event.getX();
                    downPoint.y = event.getY();
                    break;
                case MotionEvent.ACTION_MOVE:
                    //通知父控件不要拦截我自己的事件
                    getParent().requestDisallowInterceptTouchEvent(true);
                    break;
            }
            return super.onTouchEvent(event);
        }
    }
    

    至此第一个需求算是基本解决吧,不过圆角的效果并没有实现。试着将画笔改为圆滑后,数值显示会有问题,所以放弃了圆角

    需求二:

    直接上图:


    捕获.PNG

    针对LineChart,虽然支持高亮点击显示,但似乎并不知道点击的时候连接点也做相应变化,于是又开始了自定义之路。。
    自定义MyLineChart继承LineChart,MyLineChartRender继承LineChartRenderer:

    public class MyLineChart extends LineChart {
    
        public MyLineChart(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
        }
    
        public MyLineChart(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        public MyLineChart(Context context) {
            super(context);
        }
    
    
        @Override
        protected void drawMarkers(Canvas canvas) {
            // if there is no marker view or drawing marker is disabled
            if (mMarker == null || !isDrawMarkersEnabled() || !valuesToHighlight())
                return;
    
            for (int i = 0; i < mIndicesToHighlight.length; i++) {
    
                Highlight highlight = mIndicesToHighlight[i];
    
                IDataSet set = mData.getDataSetByIndex(highlight.getDataSetIndex());
    
                Entry e = mData.getEntryForHighlight(mIndicesToHighlight[i]);
                int entryIndex = set.getEntryIndex(e);
    
                // make sure entry not null
                if (e == null || entryIndex > set.getEntryCount() * mAnimator.getPhaseX())
                    continue;
    
                float[] pos = getMarkerPosition(highlight);
    
                //自定义部分,在高亮时画环形,表示选中
                Paint paint = new Paint();
                paint.setStyle(Paint.Style.FILL);//画笔为填充模式
                paint.setAntiAlias(true);//消除锯齿,使更光滑
                paint.setStrokeWidth(5);
    
                int innerRaduis = 16;//内圆半径
                int ringWidth = 16;//圆环宽度
    
    
                // check bounds这句是检查边界的,必须写在paint画圆之上,否则圆过边界不消失
                if (!mViewPortHandler.isInBounds(pos[0], pos[1]))
                    continue;
    
                //画最外层紫色圆
                paint.setColor(getResources().getColor(R.color.form_purple));
                canvas.drawCircle(pos[0], pos[1], innerRaduis+ringWidth, paint);
    
                //画中间白色露出本分环
                paint.setColor(getResources().getColor(R.color.white_fff));
                canvas.drawCircle(pos[0], pos[1], innerRaduis+ringWidth/2, paint);
    
                //画内圆
                paint.setColor(getResources().getColor(R.color.form_purple));
                canvas.drawCircle(pos[0], pos[1],innerRaduis+2 , paint);
    
    
                // callbacks to update the content
                mMarker.refreshContent(e, highlight);
    
                // draw the marker
                mMarker.draw(canvas, pos[0], pos[1]);
            }
        }
    
    
        @Override
        protected void init() {
            super.init();
    
            mRenderer = new MyLineChartRender(this, mAnimator, mViewPortHandler);
        }
    
    
        PointF downPoint = new PointF();
    
        //为解决和viewpager滑动冲突,将viewpager滑动范围缩小
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    downPoint.x = event.getX();
                    downPoint.y = event.getY();
                    break;
                case MotionEvent.ACTION_MOVE:
                    //通知父控件不要拦截我自己的事件
                    getParent().requestDisallowInterceptTouchEvent(true);
                    break;
            }
            return super.onTouchEvent(event);
        }
    }
    
    public class MyLineChartRender extends LineChartRenderer{
    
        private Path mHighlightLinePath = new Path();
    
        public MyLineChartRender(LineDataProvider chart, ChartAnimator animator, ViewPortHandler viewPortHandler) {
            super(chart, animator, viewPortHandler);
        }
    
        @Override
        protected void drawHighlightLines(Canvas c, float x, float y, ILineScatterCandleRadarDataSet set) {
            // set color and stroke-width
            mHighlightPaint.setColor(set.getHighLightColor());
            mHighlightPaint.setStrokeWidth(set.getHighlightLineWidth());
    
            // draw highlighted lines (if enabled)
            mHighlightPaint.setPathEffect(set.getDashPathEffectHighlight());
    
            // draw vertical highlight lines
            if (set.isVerticalHighlightIndicatorEnabled()) {
    
                // create vertical path
                mHighlightLinePath.reset();
    
                //自定义高亮指示线,让其不贯穿整个表格,长度为y值得高度
                mHighlightLinePath.moveTo(x, y);
                //mHighlightLinePath.moveTo(x, mViewPortHandler.contentTop());
                mHighlightLinePath.lineTo(x, mViewPortHandler.contentBottom());
    
                c.drawPath(mHighlightLinePath, mHighlightPaint);
            }
    
            // draw horizontal highlight lines
            if (set.isHorizontalHighlightIndicatorEnabled()) {
    
                // create horizontal path
                mHighlightLinePath.reset();
                mHighlightLinePath.moveTo(mViewPortHandler.contentLeft(), y);
                mHighlightLinePath.lineTo(mViewPortHandler.contentRight(), y);
    
                c.drawPath(mHighlightLinePath, mHighlightPaint);
            }
        }
    }
    

    到此,这两个小需求基本可以凑合看了。不过还有别的问题困扰着我。。。

    问题:表格的显示是切换年月的,年月的数据多少不一样,所以需要每次切换数据的时候需要重新设置缩放,并把之前缩放清空最好。

    清空缩放:

    chart.fitScreen();
    

    设置缩放:

       public static  void setScale(int size,BarLineChartBase chart){
            float radio = size / 6;//6表示当数据比较多的时候一屏显示6个label进行显示
            Matrix m = new Matrix();
            m.postScale(radio, 1f);//两个参数分别是x,y轴的缩放比例。例如:将x轴的数据放大为之前的几倍
            chart.getViewPortHandler().refresh(m, chart, false);//将图表进行缩放
        }
    

    这样解决之后,假如我滑动过快,正在拖拽的过程中马上切换年月,重新设置缩放并没有得到执行,所以即使一条数据也有可能要滑半天才能看见。对此,又找到了一对属性:

    chart.setDragDecelerationEnabled(true);//设置可以拖拽减速
    chart.setDragDecelerationFrictionCoef(0f);//减速速率设置为0,即手指松开马上停止拖拽
    

    这样拖拽的效果可能会比较死板,即手指松开表格就不滑动了,但是可以解决切换数据的问题。所以暂时就如此结尾了。

    本人经验有限,有问题的话还请多多指教,感谢阅读。

    相关文章

      网友评论

        本文标题:MPAndroidChart部分自定义效果及问题

        本文链接:https://www.haomeiwen.com/subject/totgmftx.html