本节, 我们结合官方提供的四个栗子来学习框架
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的目的是为了在图中画出不同组别的折线, 比如:
// 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;
}
}