重写MPAndroidChart显示标记

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

重写MPAndroidChart显示标记_第1张图片

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

/**
 * 数据中心的图表折线图, 继承MPChart的折线图
 * 

* 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(); // 重绘父控件, 避免残留
    }

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

重写MPAndroidChart显示标记_第2张图片

OK, Enjoy It!

你可能感兴趣的:(Work随笔)