MPAndroidChart系列源码解读(五)

本篇主要是LineChart实战相关知识和简单的源码剖析,相关源码没有,自己动手实践学习才是最有效的方法。

LineChart Simple

运行效果图

MPAndroidChart系列源码解读(五)_第1张图片

个人感官觉得某些属性设置后太难看了并没有添加,so效果图上没有显示,如果你想测试这些属性自行参考下面的api介绍

一些调用方法说明

设置图表数据内容视图的背景颜色(默认RGB(240,240,240))

mChart.setDrawGridBackground(true);
mChart.setGridBackgroundColor(Color.RED);

关于图表的描述文字,默认放在图表右下角10个像素padding,也可以自己手动设置字体、文字大小、文字显示位置等

mChart.setDescription("LineChart");
mChart.setDescriptionColor(Color.BLACK);
mChart.setDescriptionPosition(300 , 300);
mChart.setDescriptionTextSize(16);
mChart.setDescriptionTypeface(Typeface.DEFAULT_BOLD);
mChart.setNoDataTextDescription("LineChart no Data");

这里特别提示Description绘制的setDescritionPosition方法的值,并不是设置的绘制文字起始位置,而是结束位置。参考下面

MPAndroidChart系列源码解读(五)_第2张图片

Touch触摸滑动相关,如果禁用了MaskView以及点击缩放滑动都不起效果了(默认没有禁用)

 mChart.setTouchEnabled(false);

关于图表更多关于缩放相关的参考下面API

  //是否允许拖拽图表
  mChart.setDragEnabled(true);
  //是否允许缩放图表
  mChart.setScaleEnabled(true);
  //是否允许缩放X轴比例
  mChart.setScaleXEnabled(true);
  //是否允许缩放Y轴比例
  mChart.setScaleYEnabled(true);

  //setScaleEnabled方法就是禁用x、y两个轴都不能缩放如果在这个方法调用后再单独调用setScaleXEnable、setScaleYEnable

  //就没有了之前x、y轴都不能缩放的效果,单击照样能缩放。

setPinchZoom(true) 时,x y轴同时缩放坐标尺比例根据手势缩放,false测更具手势方向和是否禁止缩放判断缩放各自对应轴的刻度值比例,下图是true时的效果概念图

MPAndroidChart系列源码解读(五)_第3张图片

设置整个图表的背景色

 mChart.setBackgroundColor(Color.GRAY);

MPAndroidChart系列源码解读(五)_第4张图片

触摸图表会有个高亮的十字虚线出现和MaskView弹出,这玩意在之前blog就有提到过,这里不解释了,调用参考官方Simple

 MyMarkerView mv = new MyMarkerView(this, R.layout.custom_marker_view);
 mChart.setMarkerView(mv);

图表上添加x、y轴的轴线LimitLine,参考下面流程(LimitLine的属性set方法自己参考API即可)

  LimitLine limitLineX = new LimitLine(20,"");
  LimitLine limitLineY = new LimitLine(50,"");

  // .......config limitLine x y...............    

  XAxis xAxis = lineChart.getXAxis();
  YAxis yAxis = lineChart.getAxisLeft();

  xAxis.addLimitLine(limitLineX);
  yAxis.addLimitLine(limitLineY);

补充说明(Lable对齐位置参考LimitLabelPosition枚举,关于轴线相关API请自行参考源码,之前blog也已有过理解,不再叙述):

MPAndroidChart系列源码解读(五)_第5张图片

最后一步就是装数据设置Data,这里得注意一点,不同版本会有所变化,这里提供的是最新版本的方式setValues,MaskView之前拷贝以前下载的Simple里面的对应的有些方法不支持也需要自行参考自己版本对应类提供的方法

 public void setData(ArrayList valuesY){
        ArrayList values = new ArrayList();
        for (int i = 0; i < valuesY.size(); i++) {
            values.add(new Entry(i, valuesY.get(i)));
        }
        LineDataSet set1;
        if (lineChart.getData() != null &&
                lineChart.getData().getDataSetCount() > 0) {
            set1 = (LineDataSet) lineChart.getData().getDataSetByIndex(0);
            set1.setValues(values);
            lineChart.getData().notifyDataChanged();
            lineChart.notifyDataSetChanged();
        } else {
            set1 = new LineDataSet(values, "LimitLine 1");
            set1.enableDashedLine(10f, 5f, 0f);
            set1.enableDashedHighlightLine(10f, 5f, 0f);
           //TODO 省略config set1自行参考源代码里面的Simple,见名知其意,不过多解释
            ArrayList dataSets = new ArrayList();
            dataSets.add(set1);
            LineData data = new LineData(dataSets);
            lineChart.setData(data);
        }
    }

这里再提供一些不常用的API方法

 //设置Chart缩放的最大限度值
 mChart.getViewPortHandler().setMaximumScaleY(2f);
 mChart.getViewPortHandler().setMaximumScaleX(2f);

//移动图表位置中心
mChart.centerViewTo(200, 500, YAxis.AxisDependency.LEFT);

//图例样式配置
Legend l = mChart.getLegend();
l.setForm(LegendForm.SQUARE);//正方形、圆形、线条
l.setHorizontalAlignment(Legend.LegendHorizontalAlignment.RIGHT);//位置
l.setPosition(Legend.LegendPosition.RIGHT_OF_CHART);//位于Chart右侧

//具体使用参考枚举类相关源码

图例样式类似下图效果

补充API说明

图表上面绘制的值是否显示(LineDataSet.setDrawValues(boolean))

          List sets = mChart.getData().getDataSets();
          for (ILineDataSet iSet : sets) {
               LineDataSet set = (LineDataSet) iSet;
               set.setDrawValues(!set.isDrawValuesEnabled());
           }
          mChart.invalidate();

去掉图表绘制的填充setDrawFilled(boolean)

          List sets = mChart.getData().getDataSets();
          for (ILineDataSet iSet : sets) {
              LineDataSet set = (LineDataSet) iSet;
              if (set.isDrawFilledEnabled())
                  set.setDrawFilled(false);
              else
                  set.setDrawFilled(true);
           }
           mChart.invalidate();

MPAndroidChart系列源码解读(五)_第6张图片

控制上图的黑色小圆点的绘制setDrawCircles(boolean)

List sets = mChart.getData().getDataSets();
for (ILineDataSet iSet : sets) {
    LineDataSet set = (LineDataSet) iSet;
    if (set.isDrawCirclesEnabled())
        set.setDrawCircles(false);
    else
        set.setDrawCircles(true);
 }
 mChart.invalidate();

MPAndroidChart系列源码解读(五)_第7张图片

上图的点与点直接用虚线链接,当然这链接线的样式不知这些,更多的请参考LineDataSet类内部定义的Mode(设置方法原理同上)


    public enum Mode {
        LINEAR,
        STEPPED,
        CUBIC_BEZIER,
        HORIZONTAL_BEZIER
    }

对于触摸图表的数据对应高亮显示数据(MaskView),可以通过一个属性控制是否显示

if(mChart.getData() != null) {   
  mChart.getData().setHighlightEnabled(boolean);
  mChart.invalidate();
 }

图表的进出场动画控制可以直接通过animate方法实现

  mChart.animateX(xx);
  mChart.animateY(xx,xx);
  mChart.animateXY(xxx,xxx);

MPAndroidChart系列源码解读(五)_第8张图片

LineChart源码分析

LineChart简化版UML

MPAndroidChart系列源码解读(五)_第9张图片

LIneChart核心知识点

ChartInterface 该接口提供chart视图已知的尺寸、界限、范围等,在之前blog已有提到这里不过多解释。
BarLineScatterCandleBubbleDataProvider、LineDataProvider从继承来看都是相关属性的扩展,之前同样blog有提到,具体实现在Chart相关类里面。

LineChart Draw方法相关的无非就是drawText、drawLine这些相关方法,这里就不提了,这里呢简单说一下核心工作流程:

onTouch方法通过代理的方式处理Touch事件

public abstract class BarLineChartBase<T extends BarLineScatterCandleBubbleDataextends IBarLineScatterCandleBubbleDataSetextends Entry>>> extends Chart<T> implements BarLineScatterCandleBubbleDataProvider {

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        super.onTouchEvent(event);

        if (mChartTouchListener == null || mData == null)
            return false;

        // check if touch gestures are enabled
        if (!mTouchEnabled)
            return false;
        else
            return mChartTouchListener.onTouch(this, event);
    }


}

touch移动需要computeScroll,这个方法很久以前blog了解过了不累赘叙述具体用途

  @Override
    public void computeScroll() {

        if (mChartTouchListener instanceof BarLineChartTouchListener)
            ((BarLineChartTouchListener) mChartTouchListener).computeScroll();
    }

而ChartTouchListener仅仅是一个抽象类,很多方法都没有具体实现,具体实现在请移到这里BarLineChartTouchListener。

MPAndroidChart系列源码解读(五)_第10张图片

这里么的拖拽和缩放执行通过一些列的计算判断条件执行Matrix的postTranslate和postScale方法达到效果,当然这里面涉及到的还有模式的修改、移动的处理、高亮显示等相关事件。

至于MaskView是在什么地方被draw到图表中的呢?接着往下看..
在BarLineChartTouchListener处理touch事件引起的重绘回回到父类BarLineChartBase的onDraw方法里面,调用到父类Chart的 drawMarkers(canvas);方法,下面是具体方法块(MaskVew的绘制的和取消绘制不用多说了吧)

protected void drawMarkers(Canvas canvas) {

        // if there is no marker view or drawing marker is disabled
        if (mMarkerView == null || !mDrawMarkerViews || !valuesToHighlight())
            return;

        for (int i = 0; i < mIndicesToHighlight.length; i++) {

            Highlight highlight = mIndicesToHighlight[i];
            int xIndex = highlight.getXIndex();
            int dataSetIndex = highlight.getDataSetIndex();

            float deltaX = mXAxis != null 
                ? mXAxis.mAxisRange
                : ((mData == null ? 0.f : mData.getXValCount()) - 1.f);

            if (xIndex <= deltaX && xIndex <= deltaX * 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);

                // check bounds
                if (!mViewPortHandler.isInBounds(pos[0], pos[1]))
                    continue;

                // callbacks to update the content
                mMarkerView.refreshContent(e, highlight);

                // mMarkerView.measure(MeasureSpec.makeMeasureSpec(0,
                // MeasureSpec.UNSPECIFIED),
                // MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
                // mMarkerView.layout(0, 0, mMarkerView.getMeasuredWidth(),
                // mMarkerView.getMeasuredHeight());
                // mMarkerView.draw(mDrawCanvas, pos[0], pos[1]);

                mMarkerView.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
                        MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
                mMarkerView.layout(0, 0, mMarkerView.getMeasuredWidth(),
                        mMarkerView.getMeasuredHeight());

                if (pos[1] - mMarkerView.getHeight() <= 0) {
                    float y = mMarkerView.getHeight() - pos[1];
                    mMarkerView.draw(canvas, pos[0], pos[1] + y);
                } else {
                    mMarkerView.draw(canvas, pos[0], pos[1]);
                }
            }
        }
    }

在官方simple的Activity有实现接口OnChartGestureListener,在onChartGestureEnd方法有执行如下操作

@Override
    public void onChartGestureEnd(MotionEvent me, ChartTouchListener.ChartGesture lastPerformedGesture) {
        if(lastPerformedGesture != ChartTouchListener.ChartGesture.SINGLE_TAP)
            lineChart.highlightValues(null);
    }

如果不是轻敲的触摸了屏幕,就取消MaskView的绘制。

由于Touch的具体实现个人不想再细致分析,感觉太累就点到为止,了解大致工作流程就好。

小结

学到两点知识:

1.接口的设计

2.MaskView draw到画布

以上内容你若觉得可以欢迎点赞,记得点赞哦!本篇若有理解错误之处还望指出,以免误人子弟,有问题在个人知识范围内欢迎交流。逗逼的学习之路途漫漫,还好最近工作不忙,明天继续..

你可能感兴趣的:(Android)