MPAndroidChart系列源码解读(五)

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


LineChart Simple

运行效果图

个人感官觉得某些属性设置后太难看了并没有添加,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方法的值,并不是设置的绘制文字起始位置,而是结束位置。参考下面

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时的效果概念图

设置整个图表的背景色

 mChart.setBackgroundColor(Color.GRAY);

触摸图表会有个高亮的十字虚线出现和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也已有过理解,不再叙述):

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

 public void setData(ArrayList<Integer> valuesY){
        ArrayList<Entry> values = new ArrayList<Entry>();
        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<ILineDataSet> dataSets = new ArrayList<ILineDataSet>();
            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<ILineDataSet> sets = mChart.getData().getDataSets();
          for (ILineDataSet iSet : sets) {
               LineDataSet set = (LineDataSet) iSet;
               set.setDrawValues(!set.isDrawValuesEnabled());
           }
          mChart.invalidate();

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

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

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

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

上图的点与点直接用虚线链接,当然这链接线的样式不知这些,更多的请参考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);


LineChart源码分析

LineChart简化版UML

LIneChart核心知识点

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

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

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

public abstract class BarLineChartBase<T extends BarLineScatterCandleBubbleData<? extends IBarLineScatterCandleBubbleDataSet<? extends 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。

这里么的拖拽和缩放执行通过一些列的计算判断条件执行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到画布

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

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值