美文网首页Android开发AndroidView第三方
重写MPAndroidChart显示标记

重写MPAndroidChart显示标记

作者: SpikeKing | 来源:发表于2015-12-22 08:51 被阅读2173次

    欢迎Follow我的GitHub, 关注我的简书.

    效果

    本文的合集已经编著成书,高级Android开发强化实战,欢迎各位读友的建议和指导。在京东即可购买:https://item.jd.com/12385680.html

    Android

    MPAndroidChart是实现图表功能的优秀控件, 可以完成大多数绘制需求. 对于修改第三方库而言, 优秀的架构是继承开发, 而不是把源码拆分出去. MP在显示标记控件(MarkView)时, 会有异常, 导致标志在图表边缘显示不全, 则需要重写控件解决问题.

    继承LineChart, 提取高亮位置坐标getHighLightPos, 重绘标记drawMarkers.

    /**
     * 数据中心的图表折线图, 继承MPChart的折线图
     * <p>
     * Created by wangchenlong on 15/10/13.
     */
    public class CYDataLineChart extends LineChart {
    
        @SuppressWarnings("unused")
        private static final String TAG = "DEBUG-WCL: " + CYDataLineChart.class.getSimpleName();
    
        // 默认构造器
        public CYDataLineChart(Context context) {
            super(context);
        }
    
        public CYDataLineChart(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        public CYDataLineChart(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
        }
    
        // 获取高亮点坐标
        public float[] getHighLightPos(Entry e, Highlight highlight) {
            return getMarkerPosition(e, highlight);
        }
    
        // 重写这个方法, 修复Bug
        @Override
        protected void drawMarkers(Canvas canvas) {
    
            // if there is no marker view or drawing marker is disabled
            if (mMarkerView == null || !mDrawMarkerViews || !valuesToHighlight())
                return;
    
            Rect newRect = canvas.getClipBounds();
            newRect.inset(-80, 0);  //make the rect larger
    
            canvas.clipRect(newRect, Region.Op.REPLACE);
    
            //noinspection ForLoopReplaceableByForEach
            for (int i = 0; i < mIndicesToHighlight.length; i++) {
    
                Highlight highlight = mIndicesToHighlight[i];
                int xIndex = highlight.getXIndex();
    
                if (xIndex <= mDeltaX && xIndex <= mDeltaX * mAnimator.getPhaseX()) {
    
                    Entry e = mData.getEntryForHighlight(mIndicesToHighlight[i]);
    
                    // make sure entry not null
                    if (e == null || e.getXIndex() != mIndicesToHighlight[i].getXIndex())
                        continue;
    
                    float[] pos = getMarkerPosition(e, highlight);
    
                    // Marker偏移
                    float tmpY = pos[1] - 8 * AppUtils.getPerDp();
    
                    Paint paint = new Paint();
                    paint.setStyle(Paint.Style.FILL);
                    paint.setAntiAlias(true);
                    paint.setStrokeWidth(5);
    
                    // noinspection deprecation
                    paint.setColor(getResources().getColor(R.color.chart_circle));
                    canvas.drawCircle(pos[0], pos[1], 2 * AppUtils.getPerDp(), paint);
    
                    // check bounds
                    if (!mViewPortHandler.isInBounds(pos[0], tmpY))
                        continue;
    
                    mMarkerView.refreshContent(e, highlight);
    
                    mMarkerView.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
                            MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
                    mMarkerView.layout(0, 0, mMarkerView.getMeasuredWidth(),
                            mMarkerView.getMeasuredHeight());
    
                    if (tmpY - mMarkerView.getHeight() <= 0) {
                        float y = mMarkerView.getHeight() - tmpY;
                        mMarkerView.draw(canvas, pos[0], tmpY + y);
                    } else {
                        mMarkerView.draw(canvas, pos[0], tmpY);
                    }
                }
            }
        }
    }
    

    getMarkerPosition是LineChart类中的protected方法, 继承类, 使用public方法导出.
    float tmpY = pos[1] - 8 * AppUtils.getPerDp();, 重新计算Y坐标, 偏离原始画布.

    但是这样做有一个问题, 在移动MarkView时, 父控件会有残留. 如何解决呢? 办法就是在移动时, 重绘父控件的canvas, 使用invalidate()函数.

            // 设置图表点击事件, 监听高亮位置
            mLcChart.setOnChartValueSelectedListener(new OnChartValueSelectedListener() {
                @Override
                public void onValueSelected(Entry e, int dataSetIndex, Highlight h) {
                    int index = e.getXIndex();
                    Log.e(TAG, "index = " + index);
                    setChartIndex(index);
                    mCallback.setCurIndex(index);
                    mIndex = index;
    
                    float[] pos = mLcChart.getHighLightPos(e, h);
                    Log.e(TAG, "x: " + pos[0] + ", y: " + pos[1]);
    
                    mLlContainer.invalidate(); // 重绘父控件, 避免残留
                }
    
                @Override
                public void onNothingSelected() {
                    // 再次点击时调用这个, 要不非高亮
                    mLcChart.highlightValue(mIndex, 0);
                }
            });
    
        // 外部设置图表高亮
        private void setChartHighlight(int index) {
            if (mLcChart.getData() == null) return;
    
            mMarkerView.setDateText(mMarkers.get(index));
            mLcChart.highlightValue(index, 0);
    
            mLlContainer.invalidate(); // 重绘父控件, 避免残留
        }
    

    在图表控件中, 内部外部都会触发高亮位置.

    动画

    OK, Enjoy It!

    相关文章

      网友评论

      • aliasenor:楼主 放一个github上 我们参考一下呗,整出来不对呀
      • aliasenor:期待修改后的开源~
      • 1琥珀川1:同问 下面X轴的日期背景是怎么弄上去的?求解。。。。。。
      • 365ce88568d9:下面X轴的日期背景是怎么弄上去的?求解。。。。。。
      • e88244bf7892:楼主,请教如何默认在某个点显示markview呢,而不是通过点击
      • 45506489ab11:你好,请教一个问题,mpchart点击每一个点的时候,如何设置高亮的时候,只显示竖线,我找了很久都不行,请教下
      • 暴躁的春哥:可以告知下AppUtils.getPerDp() 该方法么?
      • Karma1026:好像春雨计步器那个app里面的历史数据折线图,自己最近也是做这个,刚开始用mpandroidchart,后来改成自己自定义了
      • a9e49c7844b7:你好,想请教一下你X轴对应的日期跟英文为两行,并且选择后第二行高亮是使用的XAxis的标签,还是说这两个是你文章里所说的外部控件?可以简单说下思路么,谢谢
      • 彩娇:有这个的demo?发给我看下,我也需要这种效果
      • jasonkxs:我想请教楼主一个问题,在linechart中如何让第一个折线点自动显示markview,后面根据点击或者滑动显示另外一个,我发现没有这个自动显示的方法,多谢赐教
        4640f78109a4:@jasonkxs 这个问题你解决了吗?我这也是需要在指定位置显示一个view,还能点击跳转页面
      • e23b321036e2:最近要用图表,在指定的位置上面显示标签,我刚使用的是mpandroidchart,请教楼主,AppUtils是什么,还有mLlContainer等在哪里创建的。最好有demo。楼主好人,我是一个入android时间不长的小白,求科普。
        SpikeKing:@飞扬的紫风 等忙完这段的, 我优先提取这个, 放心哈~, 再通知你~
        e23b321036e2:@SpikeKing 嗯,我之前用的achartengine,最近换了这个,坐等大神代码归来,mpchart每次重新绘图,还要所有属性重新设置,否则会带有,clear方法不怎么好使。坐等大神指导了。
        SpikeKing:@飞扬的紫风 这是大致的逻辑,demo还没写,是线上的项目,有时间补一个吧,最近有点忙
      • jasonkxs:话说你这个是啥应用呢?
      • jasonkxs:mLlContainer该控件是chart外面的父控件吗?
      • jasonkxs:请问该方法获取的是啥?AppUtils.getPerDp() 这个是获取多少的DP?
        SpikeKing:@jasonkxs 一个, 8是8dp
      • 梓煜:感谢发布这么多干货,持续关注中。
      • 曾樑:一大早就有教程:kissing_heart:
        SpikeKing:@曾樑 3Q!

      本文标题:重写MPAndroidChart显示标记

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