MPAndroid的LineChart

本节, 我们结合官方提供的四个栗子来学习框架
LineChartActivity1
LineChartActivity2
LineChartActivityColored

LineChartActivity1

首先在onCreat方法中进行一些基本的初始化操作, 里面涉及的知识点还真不少

  • 隐藏手机状态栏
//手机状态栏隐藏
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
  • MPAndroid的交互
/*首先是一些开关变量, 控制是否能执行相应的交互*/
// enable touch gestures, 交互的总开关, 关闭它所有交互免谈
mChart.setTouchEnabled(true);

// enable dragging
mChart.setDragEnabled(true);
// 同时打开X轴和Y轴的scale
mChart.setScaleEnabled(true);
// mChart.setScaleXEnabled(true);
// mChart.setScaleYEnabled(true);

// 这个和scale的区别在于, scale是它的前提, 打开后可以通过两个手指把图表进行放大, 关闭后只能进行X轴或Y轴方向上的放大
mChart.setPinchZoom(true);

//手势监听, 可以判断不同的动作, 比如, 长按 双击 单击 放大 平移等
mChart.setOnChartGestureListener(this);
//值选择监听器
mChart.setOnChartValueSelectedListener(this);

@Override
public void onChartGestureStart(MotionEvent me, ChartTouchListener.ChartGesture lastPerformedGesture) {
    Log.i("Gesture", "START, x: " + me.getX() + ", y: " + me.getY());
}

@Override
public void onChartGestureEnd(MotionEvent me, ChartTouchListener.ChartGesture lastPerformedGesture) {
    /*    public enum ChartGesture {
        NONE, DRAG, X_ZOOM, Y_ZOOM, PINCH_ZOOM, ROTATE, SINGLE_TAP, DOUBLE_TAP, LONG_PRESS, FLING
    }*/
    Log.i("Gesture", "END, lastGesture: " + lastPerformedGesture);

    // un-highlight values after the gesture is finished and no single-tap
    // 只有在单击事件下才会触发值选择监听器
    if(lastPerformedGesture != ChartTouchListener.ChartGesture.SINGLE_TAP)
        mChart.highlightValues(null); // or highlightTouch(null) for callback to onNothingSelected(...)
}

@Override
public void onChartLongPressed(MotionEvent me) {
    Log.i("LongPress", "Chart longpressed.");
}

@Override
public void onChartDoubleTapped(MotionEvent me) {
    Log.i("DoubleTap", "Chart double-tapped.");
}

@Override
public void onChartSingleTapped(MotionEvent me) {
    Log.i("SingleTap", "Chart single-tapped.");
}

@Override
public void onChartFling(MotionEvent me1, MotionEvent me2, float velocityX, float velocityY) {
    Log.i("Fling", "Chart flinged. VeloX: " + velocityX + ", VeloY: " + velocityY);
}

@Override
public void onChartScale(MotionEvent me, float scaleX, float scaleY) {
    Log.i("Scale / Zoom", "ScaleX: " + scaleX + ", ScaleY: " + scaleY);
}

@Override
public void onChartTranslate(MotionEvent me, float dX, float dY) {
    Log.i("Translate / Move", "dX: " + dX + ", dY: " + dY);
}

@Override
public void onValueSelected(Entry e, Highlight h) {
    Log.i("Entry selected", e.toString());
    Log.i("LOWHIGH", "low: " + mChart.getLowestVisibleX() + ", high: " + mChart.getHighestVisibleX());
    Log.i("MIN MAX", "xmin: " + mChart.getXChartMin() + ", xmax: " + mChart.getXChartMax() + ", ymin: " + mChart.getYChartMin() + ", ymax: " + mChart.getYChartMax());
}

@Override
public void onNothingSelected() {
    Log.i("Nothing selected", "Nothing selected.");
}
  • 设置markView
// create a custom MarkerView (extend MarkerView) and specify the layout
// to use for it
MyMarkerView mv = new MyMarkerView(this, R.layout.custom_marker_view);
mv.setChartView(mChart); // For bounds control, 提供一个视图的弱应用
mChart.setMarker(mv); // Set the marker to the chart

public class MyMarkerView extends MarkerView {

    private TextView tvContent;

    public MyMarkerView(Context context, int layoutResource) {
        super(context, layoutResource);

        tvContent = (TextView) findViewById(R.id.tvContent);
    }

    // callbacks everytime the MarkerView is redrawn, can be used to update the
    // content (user-interface)
    @Override
    public void refreshContent(Entry e, Highlight highlight) {

        if (e instanceof CandleEntry) {

            CandleEntry ce = (CandleEntry) e;

            tvContent.setText("" + Utils.formatNumber(ce.getHigh(), 0, true));
        } else {

            tvContent.setText("" + Utils.formatNumber(e.getY(), 0, true));
        }
        // 必须在最后调用
        super.refreshContent(e, highlight);
    }

    @Override
    public MPPointF getOffset() {
        // 控制markview的位置
        return new MPPointF(-(getWidth() / 2), -getHeight());
    }
}
  • 高亮
    所谓高亮就是使某个Entry突出, 表现在显示一个十字光标和markview.
    高亮触发条件: 拖拽打开 单击打开 代码构造
    高亮个性化设置: 在LineDataSet中设置
// 设置高亮十字光标线的虚化
set1.enableDashedHighlightLine(10f, 5f, 0f);
// 设置十字光标线的颜色
set1.setHighLightColor(Color.BLUE);

还有与高亮相关的交互在交互一节中已经涉及

@Override
public void onValueSelected(Entry e, Highlight h) {
    Log.i("Entry selected", e.toString());
    Log.i("LOWHIGH", "low: " + mChart.getLowestVisibleX() + ", high: " + mChart.getHighestVisibleX());
    Log.i("MIN MAX", "xmin: " + mChart.getXChartMin() + ", xmax: " + mChart.getXChartMax() + ", ymin: " + mChart.getYChartMin() + ", ymax: " + mChart.getYChartMax());
}

@Override
public void onNothingSelected() {
    Log.i("Nothing selected", "Nothing selected.");
}
  • X轴Y轴和LimitLine(经常用来指示上限和下限)
    轴的基本元素是: 轴线 刻度标识 网栅线, 各个部分都可以控制关闭.
    除了控制各个部分的开关, 还可以进行个性化设置:
    轴线-->设置轴的值范围, 设置轴线颜色, 宽度,等等
    刻度标识-->设置刻度个数, 设置刻度显示位置, 设置刻度字体, 格式等等
    网栅线-->设置网栅宽度, 颜色等等
    跟轴相关的还有一个limitLine的概念, 用来标识一种限制线
// x-axis limit line
LimitLine llXAxis = new LimitLine(10f, "Index 10");
llXAxis.setLineWidth(4f);
// 设置虚线
llXAxis.enableDashedLine(10f, 10f, 0f);
// "Index 10"位于右下方
llXAxis.setLabelPosition(LimitLabelPosition.RIGHT_BOTTOM);
llXAxis.setTextSize(10f);

XAxis xAxis = mChart.getXAxis();
xAxis.enableGridDashedLine(10f, 10f, 0f);
// 设置标识格式
//xAxis.setValueFormatter(new MyCustomXAxisValueFormatter());
// 轴添加LimitLIne
xAxis.addLimitLine(llXAxis); // add x-axis limit line
        
//获取字体
Typeface tf = Typeface.createFromAsset(getAssets(), "OpenSans-Regular.ttf");

LimitLine ll1 = new LimitLine(150f, "Upper Limit");
ll1.setLineWidth(4f);
ll1.enableDashedLine(10f, 10f, 0f);
ll1.setLabelPosition(LimitLabelPosition.RIGHT_TOP);
ll1.setTextSize(10f);
//设置字体
ll1.setTypeface(tf);

LimitLine ll2 = new LimitLine(-30f, "Lower Limit");
ll2.setLineWidth(4f);
ll2.enableDashedLine(10f, 10f, 0f);
ll2.setLabelPosition(LimitLabelPosition.RIGHT_BOTTOM);
ll2.setTextSize(10f);
ll2.setTypeface(tf);

YAxis leftAxis = mChart.getAxisLeft();
leftAxis.removeAllLimitLines(); // reset all limit lines to avoid overlapping lines
leftAxis.addLimitLine(ll1);
leftAxis.addLimitLine(ll2);
// 设置Y轴的最大最小范围
leftAxis.setAxisMaximum(200f);
leftAxis.setAxisMinimum(-50f);
//leftAxis.setYOffset(20f);
// 虚线栅格线
leftAxis.enableGridDashedLine(10f, 10f, 0f);
// 0值线
leftAxis.setDrawZeroLine(false);

// limit lines are drawn behind data (and not on top)
leftAxis.setDrawLimitLinesBehindData(true);

mChart.getAxisRight().setEnabled(false);
  • 填充数据
    基本设置完了以后就可以填充数据进行画图了.
    这里区分两个概念: LineData和LineDataSet, 一个LineChart只有一个lineData, 但可以有多个LineDataSet.
    设计LineDataSet的目的是为了在图中画出不同组别的折线, 比如:
MPAndroid的LineChart_第1张图片
image
// add data
setData(45, 100);

// mChart.setVisibleXRange(20);
// mChart.setVisibleYRange(20f, AxisDependency.LEFT);
// mChart.centerViewTo(20, 50, AxisDependency.LEFT);

//开启动画会自动刷新图表
mChart.animateX(2500);
//mChart.invalidate();

// get the legend (only possible after setting data)
Legend l = mChart.getLegend();
// modify the legend ...
l.setForm(LegendForm.LINE);

// // dont forget to refresh the drawing
// mChart.invalidate();


private void setData(int count, float range) {

        ArrayList values = new ArrayList();

        for (int i = 0; i < count; i++) {

            float val = (float) (Math.random() * range) + 3;
            //在单元数据中添加图片标志
            values.add(new Entry(i, val, getResources().getDrawable(R.drawable.star)));
        }

        LineDataSet set1;

        if (mChart.getData() != null &&
                mChart.getData().getDataSetCount() > 0) {
            set1 = (LineDataSet)mChart.getData().getDataSetByIndex(0);
            set1.setValues(values);
            //通知数据发生变化
            mChart.getData().notifyDataChanged();
            mChart.notifyDataSetChanged();
        } else {
            // create a dataset and give it a type
            set1 = new LineDataSet(values, "DataSet 1");

            set1.setDrawIcons(false);

            // set the line to be drawn like this "- - - - - -"
            set1.enableDashedLine(10f, 5f, 0f);
            set1.enableDashedHighlightLine(10f, 5f, 0f);
            set1.setColor(Color.BLACK);
            set1.setCircleColor(Color.BLACK);
            set1.setLineWidth(1f);
            set1.setCircleRadius(3f);
            set1.setDrawCircleHole(false);
            set1.setValueTextSize(9f);
            set1.setDrawFilled(true);
            //设置图例线宽
            set1.setFormLineWidth(1f);
            //设置图例线型
            set1.setFormLineDashEffect(new DashPathEffect(new float[]{10f, 5f}, 0f));
            //设置图例标识
            set1.setFormSize(15.f);

            if (Utils.getSDKInt() >= 18) {
                // fill drawable only supported on api level 18 and above
                Drawable drawable = ContextCompat.getDrawable(this, R.drawable.fade_red);
                set1.setFillDrawable(drawable);
            }
            else {
                set1.setFillColor(Color.BLACK);
            }

            ArrayList dataSets = new ArrayList();
            dataSets.add(set1); // add the datasets

            // create a data object with the datasets
            LineData data = new LineData(dataSets);

            // set data
            mChart.setData(data);
        }
    }
  • 动态操作图表
    所谓动态操作图表, 其思路就是取得图表的数据集进行一些个性化设置, 然后通知图表刷新.
    除了高亮显示是设置LineData, 其余设置都是设置LineDataSet数据集.
public boolean onOptionsItemSelected(MenuItem item) {

        switch (item.getItemId()) {
            case R.id.actionToggleValues: {
                List sets = mChart.getData()
                        .getDataSets();

                for (ILineDataSet iSet : sets) {

                    LineDataSet set = (LineDataSet) iSet;
                    set.setDrawValues(!set.isDrawValuesEnabled());
                }

                mChart.invalidate();
                break;
            }
            case R.id.actionToggleIcons: {
                List sets = mChart.getData()
                        .getDataSets();

                for (ILineDataSet iSet : sets) {

                    LineDataSet set = (LineDataSet) iSet;
                    set.setDrawIcons(!set.isDrawIconsEnabled());
                }

                mChart.invalidate();
                break;
            }
            case R.id.actionToggleHighlight: {
                if(mChart.getData() != null) {
                    mChart.getData().setHighlightEnabled(!mChart.getData().isHighlightEnabled());
                    mChart.invalidate();
                }
                break;
            }
            case R.id.actionToggleFilled: {

                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();
                break;
            }
            case R.id.actionToggleCircles: {
                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();
                break;
            }
            case R.id.actionToggleCubic: {
                List sets = mChart.getData()
                        .getDataSets();

                for (ILineDataSet iSet : sets) {

                    LineDataSet set = (LineDataSet) iSet;
                    set.setMode(set.getMode() == LineDataSet.Mode.CUBIC_BEZIER
                            ? LineDataSet.Mode.LINEAR
                            :  LineDataSet.Mode.CUBIC_BEZIER);
                }
                mChart.invalidate();
                break;
            }
            case R.id.actionToggleStepped: {
                List sets = mChart.getData()
                        .getDataSets();

                for (ILineDataSet iSet : sets) {

                    LineDataSet set = (LineDataSet) iSet;
                    set.setMode(set.getMode() == LineDataSet.Mode.STEPPED
                            ? LineDataSet.Mode.LINEAR
                            :  LineDataSet.Mode.STEPPED);
                }
                mChart.invalidate();
                break;
            }
            case R.id.actionToggleHorizontalCubic: {
                List sets = mChart.getData()
                        .getDataSets();

                for (ILineDataSet iSet : sets) {

                    LineDataSet set = (LineDataSet) iSet;
                    set.setMode(set.getMode() == LineDataSet.Mode.HORIZONTAL_BEZIER
                            ? LineDataSet.Mode.LINEAR
                            :  LineDataSet.Mode.HORIZONTAL_BEZIER);
                }
                mChart.invalidate();
                break;
            }
            case R.id.actionTogglePinch: {
                if (mChart.isPinchZoomEnabled())
                    mChart.setPinchZoom(false);
                else
                    mChart.setPinchZoom(true);

                mChart.invalidate();
                break;
            }
            case R.id.actionToggleAutoScaleMinMax: {
                mChart.setAutoScaleMinMaxEnabled(!mChart.isAutoScaleMinMaxEnabled());
                mChart.notifyDataSetChanged();
                break;
            }
            case R.id.animateX: {
                mChart.animateX(3000);
                break;
            }
            case R.id.animateY: {
                mChart.animateY(3000, Easing.EasingOption.EaseInCubic);
                break;
            }
            case R.id.animateXY: {
                mChart.animateXY(3000, 3000);
                break;
            }
            case R.id.actionSave: {
                if (mChart.saveToPath("title" + System.currentTimeMillis(), "")) {
                    Toast.makeText(getApplicationContext(), "Saving SUCCESSFUL!",
                            Toast.LENGTH_SHORT).show();
                } else
                    Toast.makeText(getApplicationContext(), "Saving FAILED!", Toast.LENGTH_SHORT)
                            .show();

                // mChart.saveToGallery("title"+System.currentTimeMillis())
                break;
            }
        }
        return true;
    }
LineChartActivity2

次栗子和上述相比差不太多, 区别在于双Y轴显示, 多条折线显示, 其实也就是多了几个LineDataSet而已.

private void setData(int count, float range) {

        ArrayList yVals1 = new ArrayList();

        for (int i = 0; i < count; i++) {
            float mult = range / 2f;
            float val = (float) (Math.random() * mult) + 50;
            yVals1.add(new Entry(i, val));
        }

        ArrayList yVals2 = new ArrayList();

        for (int i = 0; i < count-1; i++) {
            float mult = range;
            float val = (float) (Math.random() * mult) + 450;
            yVals2.add(new Entry(i, val));
//            if(i == 10) {
//                yVals2.add(new Entry(i, val + 50));
//            }
        }

        ArrayList yVals3 = new ArrayList();

        for (int i = 0; i < count; i++) {
            float mult = range;
            float val = (float) (Math.random() * mult) + 500;
            yVals3.add(new Entry(i, val));
        }

        LineDataSet set1, set2, set3;

        if (mChart.getData() != null &&
                mChart.getData().getDataSetCount() > 0) {
            set1 = (LineDataSet) mChart.getData().getDataSetByIndex(0);
            set2 = (LineDataSet) mChart.getData().getDataSetByIndex(1);
            set3 = (LineDataSet) mChart.getData().getDataSetByIndex(2);
            set1.setValues(yVals1);
            set2.setValues(yVals2);
            set3.setValues(yVals3);
            mChart.getData().notifyDataChanged();
            mChart.notifyDataSetChanged();
        } else {
            // create a dataset and give it a type
            set1 = new LineDataSet(yVals1, "DataSet 1");

            set1.setAxisDependency(AxisDependency.LEFT);
            set1.setColor(ColorTemplate.getHoloBlue());
            set1.setCircleColor(Color.WHITE);
            set1.setLineWidth(2f);
            set1.setCircleRadius(3f);
            set1.setFillAlpha(65);
            set1.setFillColor(ColorTemplate.getHoloBlue());
            set1.setHighLightColor(Color.rgb(244, 117, 117));
            set1.setDrawCircleHole(false);
            //set1.setFillFormatter(new MyFillFormatter(0f));
            //set1.setDrawHorizontalHighlightIndicator(false);
            //set1.setVisible(false);
            //set1.setCircleHoleColor(Color.WHITE);

            // create a dataset and give it a type
            set2 = new LineDataSet(yVals2, "DataSet 2");
            set2.setAxisDependency(AxisDependency.RIGHT);
            set2.setColor(Color.RED);
            set2.setCircleColor(Color.WHITE);
            set2.setLineWidth(2f);
            set2.setCircleRadius(3f);
            set2.setFillAlpha(65);
            set2.setFillColor(Color.RED);
            set2.setDrawCircleHole(false);
            set2.setHighLightColor(Color.rgb(244, 117, 117));
            //set2.setFillFormatter(new MyFillFormatter(900f));

            set3 = new LineDataSet(yVals3, "DataSet 3");
            set3.setAxisDependency(AxisDependency.RIGHT);
            set3.setColor(Color.YELLOW);
            set3.setCircleColor(Color.WHITE);
            set3.setLineWidth(2f);
            set3.setCircleRadius(3f);
            set3.setFillAlpha(65);
            set3.setFillColor(ColorTemplate.colorWithAlpha(Color.YELLOW, 200));
            set3.setDrawCircleHole(false);
            set3.setHighLightColor(Color.rgb(244, 117, 117));

            // create a data object with the datasets
            LineData data = new LineData(set1, set2, set3);
            data.setValueTextColor(Color.WHITE);
            data.setValueTextSize(9f);

            // set data
            mChart.setData(data);
        }
    }
LineChartActivityColored

这个也没啥好说的, 关键点在注释中

public class LineChartActivityColored extends DemoBase {

    private LineChart[] mCharts = new LineChart[4];
    private Typeface mTf;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);
        setContentView(R.layout.activity_colored_lines);

        mCharts[0] = (LineChart) findViewById(R.id.chart1);
        mCharts[1] = (LineChart) findViewById(R.id.chart2);
        mCharts[2] = (LineChart) findViewById(R.id.chart3);
        mCharts[3] = (LineChart) findViewById(R.id.chart4);

        mTf = Typeface.createFromAsset(getAssets(), "OpenSans-Bold.ttf");

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

            LineData data = getData(36, 100);
            data.setValueTypeface(mTf);

            // add some transparency to the color with "& 0x90FFFFFF"
            setupChart(mCharts[i], data, mColors[i % mColors.length]);
        }
    }

    private int[] mColors = new int[] {
            Color.rgb(137, 230, 81), 
            Color.rgb(240, 240, 30), 
            Color.rgb(89, 199, 250),
            Color.rgb(250, 104, 104)
    };

    private void setupChart(LineChart chart, LineData data, int color) {

        ((LineDataSet) data.getDataSetByIndex(0)).setCircleColorHole(color);

        // no description text
        chart.getDescription().setEnabled(false);
        
        // mChart.setDrawHorizontalGrid(false);
        //
        // enable / disable grid background
        chart.setDrawGridBackground(false);
//        chart.getRenderer().getGridPaint().setGridColor(Color.WHITE & 0x70FFFFFF);

        // enable touch gestures
        chart.setTouchEnabled(true);

        // enable scaling and dragging
        chart.setDragEnabled(true);
        chart.setScaleEnabled(true);

        // if disabled, scaling can be done on x- and y-axis separately
        chart.setPinchZoom(false);

        chart.setBackgroundColor(color);
        
        // set custom chart offsets (automatic offset calculation is hereby disabled)
        // 这里设置的意义在于使左右边界的圆圈不被遮挡
        chart.setViewPortOffsets(10, 0, 10, 0);

        // add data
        chart.setData(data);

        // get the legend (only possible after setting data)
        Legend l = chart.getLegend();
        l.setEnabled(false);

        chart.getAxisLeft().setEnabled(false);
        // 设置轴上下空间大小
        chart.getAxisLeft().setSpaceTop(40);
        chart.getAxisLeft().setSpaceBottom(40);
        chart.getAxisRight().setEnabled(false);

        chart.getXAxis().setEnabled(false);

        // animate calls invalidate()...
        chart.animateX(2500);
    }
    
    private LineData getData(int count, float range) {

        ArrayList yVals = new ArrayList();

        for (int i = 0; i < count; i++) {
            float val = (float) (Math.random() * range) + 3;
            yVals.add(new Entry(i, val));
        }

        // create a dataset and give it a type
        LineDataSet set1 = new LineDataSet(yVals, "DataSet 1");
        // set1.setFillAlpha(110);
        // set1.setFillColor(Color.RED);

        set1.setLineWidth(1.75f);
        set1.setCircleRadius(5f);
        set1.setCircleHoleRadius(2.5f);
        set1.setColor(Color.WHITE);
        set1.setCircleColor(Color.WHITE);
        set1.setHighLightColor(Color.WHITE);
        set1.setDrawValues(false);

        // create a data object with the datasets
        LineData data = new LineData(set1);

        return data;
    }
}

你可能感兴趣的:(MPAndroid的LineChart)