• 重写MPAndroidChart显示标记


    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!

  • 相关阅读:
    linux | 管道符、输出重定向
    php 升级php5.5 、php7
    mysql 启动失败
    centos7.2安装phpmyadmin
    php file_get_contents失败[function.file-get-contents]: failed to open stream: HTTP request failed!解决
    go println与printf区别
    前端 head 中mate 详解
    centos 7 安装mysql
    iOS数据持久化—数据库SQLite模糊查询
    C 语言字符串和格式化输入与输出
  • 原文地址:https://www.cnblogs.com/jhcelue/p/7061164.html
Copyright © 2020-2023  润新知