美文网首页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点击每一个点的时候,如何设置高亮的时候,只显示竖线,我找了很久都不行,请教下
  • addf7fb9db9d:可以告知下AppUtils.getPerDp() 该方法么?
  • Karma1026:好像春雨计步器那个app里面的历史数据折线图,自己最近也是做这个,刚开始用mpandroidchart,后来改成自己自定义了
  • a9e49c7844b7:你好,想请教一下你X轴对应的日期跟英文为两行,并且选择后第二行高亮是使用的XAxis的标签,还是说这两个是你文章里所说的外部控件?可以简单说下思路么,谢谢
  • f29c19805e8f:有这个的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
  • bb1ad91703d5:感谢发布这么多干货,持续关注中。
  • 曾樑:一大早就有教程:kissing_heart:
    SpikeKing:@曾樑 3Q!

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

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