文章目录

  • 前言
  • 举例说明一些概念
  • Chart设置
    • 补充1:ViewPortHandler类
    • 补充2:设置空数据文案
    • 补充3:设置触摸监听并打印当前坐标
    • 补充4:给chart设置一组数据
      • 折线图示例
      • 柱状图示例
      • 饼状图示例
    • 补充5:关于设置高亮数据
    • 补充6:设置x轴标签换行
  • ChartData
    • 刷新列表的2种方式
  • ComponentBase
    • Description
    • LimitLine
    • Legend
      • 设置自定义图例
      • 设置图例自动换行
    • AxisBase
  • MarkerView
    • 补充:使用SpannableStringBuilder显示不一样的字体
  • 问题记录
    • 问题1:无法在MPAndroidChart中设置Double值
    • 问题2:ValueFormatter处出错ArrayIndexOutOfBoundsException
  • AAChart
  • 后话

前言

说到图表,我第一时间就想到了大名鼎鼎的MPAndroidChart,这个库在在IOS端叫Charts。如果是网页端,ECharts库很好用。
本文中使用库版本为MPAdnroidChart库3.1.0。

举例说明一些概念

  • Chart是一个ViewGroup,这和我们了解的大部分自定义View相同。
  • 上图为BarChart,简单说明下:x轴、左边的y轴、右边的y轴(上图没显示)、x轴的标签(上图 1980、1982…)、左边y轴标签(上图 0、40、80…)、图例(说明有几个数据集)、LimitLine(上图为y轴上的加粗虚线,文案为Good Level)、网格线(上图只在x轴上绘制了网格线,而且网格线默认是实线,与坐标垂直)、数据(上图条型柱)
  • MarkerView:可以简单理解为,自定义的弹出界面,见下图
  • ValueFormatter使用,可以处理x、y轴标签文案显示,还可以处理markerview弹出框中文案显示。
  • Entry这个东西是必带 x、y坐标的,还可以附带一个Object对象,作用当然是使用ValueFormatter时,根据对象和坐标值显示文案。

Chart设置

提示:下面的设置有许多是可以注释掉的,因为是默认值

//设置viewgroup背景色
chart.setBackgroundColor(Color.WHITE);
//设置绘制网格背景
chart.setDrawGridBackground(true);
//设置网格背景色
chart.setGridBackgroundColor(Color.BLUE);
//设置不绘制边框
//chart.setDrawBorders(false);//设置图表上启用了触摸手势
//chart.setTouchEnabled(true);
//设置可以缩放图表
//chart.setScaleEnabled(true);
//设置可以用手指移动图表
//chart.setDragEnabled(true);
//设置启用捏缩放标志
chart.setPinchZoom(true);//不显示图表描述文字
chart.getDescription().setEnabled(false);
//不显示x轴
chart.getXAxis().setEnabled(false);
//不显示右边y轴
chart.getAxisRight().setEnabled(false);
//不显示左边y轴
chart.getAxisLeft().setEnabled(false);
//不显示图例
chart.getLegend().setEnabled(false);//设置makerview,即选中值时出现的标志显示框,一般是自定义
//...省略了MarkerView创建过程
chart.setMarker(mv);//返回代表所有x标签的对象
XAxis xAxis = chart.getXAxis();
//返回左侧的y轴对象
YAxis yAxisLeft=chart.getAxisLeft();
//返回右侧y轴对象
YAxis yAxisRight=chart.getAxisRight();//执行默认动画在X轴上对图表进行渲染,时长1.5s
chart.animateX(1500);
//执行默认动画在Y轴上对图表进行渲染,时长1.5s
chart.animateY(1500);
//执行默认动画分别在X轴和Y轴上对图表进行渲染
chart.animateXY(1500,1500);
//默认动画是线形的,具体查看com.github.mikephil.charting.animation.Easing类
//执行指定动画在Y轴上对图表进行渲染,时长2s
chart.animateY(2000, Easing.EaseInCubic);//获取图表的图例对象
chart.getLegend();//获取所有数据
//获取的是一个ChartData类型的对象,ChartData内有一个列表,它可以存储任意实现了IDataSet接口的对象,比如说BarDataSet、LineDataSet、PinDataSet这些。关于数据和数据集我们后面再说。
chart.getData()//设置所有数据  data必须是ChartData类型,像LinData、BarData、PieData这些都是ChartData的子类。
chart.setData(data);

补充1:ViewPortHandler类

chart类内部有一个ViewPortHandler对象,他存储着可绘制图形区域、允许最大拖曳距离、允许最大比率、当前平移位置等。

示例-让当前chart x轴放大四倍、y轴不变

//新建一个矩阵
Matrix matrix = new Matrix();
// x轴放大4倍,y不变
matrix.postScale(4.0f, 1.0f);
chart.getViewPortHandler().refresh(matrix, mChart, true);

补充2:设置空数据文案

 /*** 显示无数据的提示** @param mChart*/
public static void showNoDataText(Chart chart) {chart.clear();chart.notifyDataSetChanged();chart.setNoDataText("没有数据");chart.setNoDataTextColor(Color.WHITE);// 记得最后要刷新一下chart.invalidate();
}

补充3:设置触摸监听并打印当前坐标

//先确保图表允许触摸事件
chart.setTouchEnabled(true);
//设置监听
chart.setOnChartValueSelectedListener(new OnChartValueSelectedListener() {@Overridepublic void onValueSelected(Entry e, Highlight h) {//打印坐标Log.i("Entry selected", e.toString());}@Overridepublic void onNothingSelected() {Log.i("Nothing selected", "Nothing selected.");}
});

补充4:给chart设置一组数据

折线图示例

//造一点数据,每一个数据点都绑定一个水费信息WaterInfo
ArrayList<Entry> values = new ArrayList<>();
for (int i = 0; i < 45; i++) {float val = (float) (Math.random() * 200);values.add(new Entry(i, val, new WaterInfo(i,i*0.5f)));
}
LineDataSet lineDataSetWater;
//创建一个line数据集并设置label字段
lineDataSetWater = new LineDataSet(values, "lineDataSetWater");
//设置不绘制每个数据节点的小图标 常用于数据源是BarEntry(float float y, Drawable icon)这种类型的
lineDataSetWater.setDrawIcons(false);
//设置模式为贝塞尔曲线线
lineDataSetWater.setMode(LineDataSet.Mode.HORIZONTAL_BEZIER);
//设置数据线为虚线 默认是实线
lineDataSetWater.enableDashedLine(10f, 5f, 0f);
//设置不显示数据值
lineDataSetWater.setDrawValues(false);
//设置显示数据值字体大小
lineDataSetWater.setValueTextSize(10f);
//设置曲线颜色
lineDataSetWater.setColor(Color.BLACK);
//设置画圆点
lineDataSetWater.setDrawCircles(true);
//设置不画圆心,即画实心圆点
lineDataSetWater.setDrawCircleHole(false);
//设置圆点的半径
lineDataSetWater.setCircleRadius(3f);
//设置圆点颜色
lineDataSetWater.setCircleColor(Color.RED);
//设置线宽
lineDataSetWater.setLineWidth(1f);
//不显示选中指示线  默认显示
//lineDataSetWater.disableDashedLine();
//设置选中指示线为虚线
lineDataSetWater.enableDashedHighlightLine(10f, 5f, 0f);
//设置允许填充线到坐标轴的区域
lineDataSetWater.setDrawFilled(true);
lineDataSetWater.setFillFormatter(new IFillFormatter() {@Overridepublic float getFillLinePosition(ILineDataSet dataSetLineDataProvider dataProvider) {return chart.getAxisLeft().getAxisMinimum();}
});
//设置填充区域
if (android.os.Build.VERSION.SDK_INT >= 18) {//设置填充区域为一个渐变红的DrawableDrawable drawable=ContextCompat.getDrawable(getBaseContext(),R.drawable.fade_red);lineDataSetWater.setFillDrawable(drawable);
} else {//设置渐变区域填充色lineDataSetWater.setFillColor(Color.BLUE);
}
ArrayList<ILineDataSet> dataSets = new ArrayList<>();
dataSets.add(lineDataSetWater);
//新建一个LineData,并加入数据集
LineData data = new LineData(dataSets);
//给图表设置数据源
chart.setData(data);

tips:如果是混合图,使用CombinedChart和CombinedData.

柱状图示例

BarChart chart =findViewById(R.id.chart);
chart = findViewById(R.id.chart1);
//设置图表背景色
chart.setBackgroundColor(Color.WHITE);
//设置不绘制阴影
chart.setDrawBarShadow(false);
//设置绘制数值
chart.setDrawValueAboveBar(true);
//设置不显示描述框
chart.getDescription().setEnabled(false);
//执行默认动画分别在X轴和Y轴上对图表进行渲染
chart.animateXY(1500,1500);
//设置监听器
chart.setOnChartValueSelectedListener(new OnChartValueSelectedListener() {private final RectF onValueSelectedRectF = new RectF();@Overridepublic void onValueSelected(Entry e, Highlight h) {if (e == null) return;RectF bounds = onValueSelectedRectF;chart.getBarBounds((BarEntry) e, bounds);MPPointF position = chart.getPosition(e, AxisDependency.LEFT);//打印矩形信息Log.i("bounds", bounds.toString());Log.i("x-index", "low: " + chart.getLowestVisibleX() + ", high: "+ chart.getHighestVisibleX());MPPointF.recycleInstance(position);}@Overridepublic void onNothingSelected() { }
});
//设置一屏最大显示数据量为19(注意是20-1,这个和显示ValuesText有点联系,尽量设置大,设置小了,ValuesText会不显示)
//只有当DataSet允许画值的时候,才有作用
chart.setMaxVisibleValueCount(20);
//设置不允许双指缩放
chart.setPinchZoom(false);//...省略设置轴线、图例、markerview等相关
ArrayList<BarEntry> values = new ArrayList<>();
for (int i = 1; i < 10; i++) {float val = (float) (Math.random() * (range + 1));if (i % 2 == 0) {//带drawable的数据源values.add(new BarEntry(i, val, getResources().getDrawable(R.drawable.star)));} else {values.add(new BarEntry(i, val));}
}
//label字段和图例相关
BarDataSet barDataSet = new BarDataSet(values, "2017");
//设置不画小图标
barDataSet.setDrawIcons(false);
int startColor1 = ContextCompat.getColor(this, android.R.color.holo_orange_light);
int startColor2 = ContextCompat.getColor(this, android.R.color.holo_blue_light);
int startColor3 = ContextCompat.getColor(this, android.R.color.holo_orange_light);
int endColor1 = ContextCompat.getColor(this, android.R.color.holo_blue_dark);
int endColor2 = ContextCompat.getColor(this, android.R.color.holo_purple);
int endColor3 = ContextCompat.getColor(this, android.R.color.holo_green_dark);List<GradientColor> gradientColors = new ArrayList<>();
gradientColors.add(new GradientColor(startColor1, endColor1));
gradientColors.add(new GradientColor(startColor2, endColor2));
gradientColors.add(new GradientColor(startColor3, endColor3));
//设置渐变色集合  集合大小随意
barDataSet.setGradientColors(gradientColors);List<Integer> colors=new ArrayList<>();
colors.add(startColor1);
colors.add(startColor2);
colors.add(startColor3);
//设置字体颜色合集,集合大小随意
barDataSet.setValueTextColors(colors);ArrayList<IBarDataSet> dataSets = new ArrayList<>();
dataSets.add(barDataSet);//创建一个bardata
BarData data = new BarData(dataSets);
//可以某个dataset单独设置,这里是设置所有ValueText
data.setDrawValues(true);
data.setValueTextSize(10f);
data.setValueTypeface(tfLight);
//设置bar的宽度百分率(默认0.85),大于1会出现柱子重叠
data.setBarWidth(0.5f);chart.setData(data);

贴个图

饼状图示例

PieChart chart=findViewById(R.id.chart);
//设置在饼图切片中显示百分比值
chart.setUsePercentValues(true);
//设置在饼图切片中显示条目信息
chart.setDrawEntryLabels(true);
//条目信息相关设置 颜色、样式、字体大小等
chart.setEntryLabelColor(Color.WHITE);
chart.setEntryLabelTypeface(tfRegular);
chart.setEntryLabelTextSize(12f);
//设置不显示描述框
chart.getDescription().setEnabled(false);
//设置图表视图左、上、右、下 额外偏移量
//此偏移量,不会影响设置了在chart外部的图例等
chart.setExtraOffsets(5, 10, 5, 5);
//设置触摸后图表继续滚动,默认为true(类比手动转大转盘,慢慢停下)
chart.setDragDecelerationEnabled(true);
//设置减速摩擦系数 默认0.9
chart.setDragDecelerationFrictionCoef(-1f);//设置绘制中间文本
chart.setDrawCenterText(true);
//设置中间文字字体样式
chart.setCenterTextTypeface(tfLight);
//设置中间字体 generateCenterSpannableText
chart.setCenterText(generateCenterSpannableText());//设置允许绘制图表中间的洞
chart.setDrawHoleEnabled(true);
//设置洞颜色
chart.setHoleColor(Color.WHITE);
//设置透明圆颜色
chart.setTransparentCircleColor(Color.WHITE);
//设置透明圆透明度
chart.setTransparentCircleAlpha(110);
//设置洞半径
chart.setHoleRadius(58f);
//设置透明圆半径
chart.setTransparentCircleRadius(61f);//允许手势触摸旋转
chart.setRotationEnabled(true);
//设置旋转偏移量,默认270f,单位:度
chart.setRotationAngle(0);
//设置允许点击手势后模块高亮
chart.setHighlightPerTapEnabled(true);//设置选中值监听器
chart.setOnChartValueSelectedListener(new OnChartValueSelectedListener() {@Overridepublic void onValueSelected(Entry e, Highlight h) {if (e == null)return;Log.i("VAL SELECTED","Value: " + e.getY() + ", index: " + h.getX()+ ", DataSet index: " + h.getDataSetIndex());}@Overridepublic void onNothingSelected() {}
});/*chart.setDrawHoleEnabled(true);
chart.setDrawSlicesUnderHole(false);
//设置以弯曲方式绘制切片,仅在启用绘制孔Hole,并且未在孔下方绘制切片的情况生效
chart.setDrawRoundedSlices(true);*/

设置数据

ArrayList<PieEntry> entries = new ArrayList<>();
for (int i = 0; i < 5 ; i++) {entries.add(new PieEntry((float) ((Math.random() * 100) + 100 / 5),"Data"+i));}PieDataSet dataSet = new PieDataSet(entries, "Election Results");
//设置不画小图标
dataSet.setDrawIcons(false);
//设置切片Slice之间空间(unit:dp)
dataSet.setSliceSpace(3f);
//设置小图表偏移集合
//  dataSet.setIconsOffset(new MPPointF(40, 40));
//设置数据集中突出显示的切片与图表中心距离 (unit:dp) 点击手势
//注意:在弯曲方式绘制切片时,此设置无效
dataSet.setSelectionShift(5f);//创建一个颜色集合
ArrayList<Integer> colors = new ArrayList<>();
//chart库自带了很多颜色集合,查看工具类utils下ColorTemplate
for (int c : ColorTemplate.COLORFUL_COLORS) colors.add(c);
//  colors.add(ColorTemplate.getHoloBlue());
//设置颜色集合dataSet.setColors(colors);//创建一个PieData
PieData data = new PieData(dataSet);
//库自带的PercentFormatter
data.setValueFormatter(new PercentFormatter(chart));
//设置数据文本字体大小
data.setValueTextSize(12f);
//设置数据文本颜色
data.setValueTextColor(Color.WHITE);
//设置数据文本样式
data.setValueTypeface(tfLight);
chart.setData(data);

补充5:关于设置高亮数据

什么是高亮值,选中值监听器的onValueSelected方法里不是返回了一个Highlight对象,他包含了要突出显示的值的一些信息。比如这个值的x值和y值、当前值在x方向像素和y方向像素、这个值的数据集在数据中的索引等。如上图突出的数据“74”,被2条坐标标记出来了。

//需要高亮的数据集设置为null
chart.highlightValues(null);
chart.invalidate();

设置dataSet或者Data的属性也可:

//LineDataSet为例
linDataSet.setHighlightEnabled(false);//LineData为例
linData.setHighlightEnabled(false);

补充6:设置x轴标签换行

x轴显示时间,格式为yyyy-MM-dd HHmmSS,要求换行显示2部分,条件为空格。

/*** 自定义AxisRenderer */
public class CustomXAxisRenderer extends XAxisRenderer {public CustomXAxisRenderer(ViewPortHandler viewPortHandler, XAxis xAxis, Transformer trans) {super(viewPortHandler, xAxis, trans);}@Overrideprotected void drawLabel(Canvas c, String formattedLabel, float x, float y, MPPointF anchor, float angleDegrees) {String[] lines = formattedLabel.split(" ");int length = lines.length;for (int i = 0; i < length; i++) {float offset = i * mAxisLabelPaint.getTextSize();Utils.drawXAxisValue(c, lines[i], x, y + offset, mAxisLabelPaint, anchor, angleDegrees);}}
}

设置

chart.setXAxisRenderer(new CustomXAxisRenderer(chart.getViewPortHandler(), xAxis,chart.getTransformer(YAxis.AxisDependency.LEFT)));

ChartData

说到ChartData就必须说IDataSet接口和Entry对象。
其内部有一个数据集列表,并且维护着x轴和y轴最大最小值:mYMax、mYMin、mXMax、mXMin,通过遍历Entry获取。

刷新列表的2种方式

  1. 刷新整个表
    可以直接调用Chart的setData方法。

  2. 部分刷新
    通过操作Entry列表,并依次调用Chart的notifyDataSetChanged和invalidate方法。

至于怎么操作Entry列表,图表中数据集可以调用下面方法

//IDataSet接口中有关方法 <T extends Entry>//添加一条数据
boolean addEntry(T e);
//移除某条数据
boolean removeEntry(T e);
//移除第一条数据
boolean removeFirst();
//移除最后一条数据
boolean removeLast();

或者直接调用ChartData中方法

//ChartData中有关方法   <T extends IDataSet<? extends Entry>>//给此数据中某个数据集添加一条数据
addEntry(Entry e, int dataSetIndex)
//从此数据中某个数据集中移除某条数据
boolean removeEntry(Entry e, int dataSetIndex)
//给此数据添加一个数据集
addDataSet(T d)
//从此数据中移除某个数据集
boolean removeDataSet(T d)

最后别忘记刷新列表

chart.notifyDataSetChanged(); // let the chart know it's data changed
chart.invalidate(); // refresh

ComponentBase

看了以下发现,AxisBase、Description、Legend、LimitLine都继承他。

设置了一些默认值,比如是否绘制、偏移量、字体大小、字体样式。

protected boolean mEnabled = true;
protected float mXOffset = 5f;
protected float mYOffset = 5f;
protected Typeface mTypeface = null;
protected float mTextSize = Utils.convertDpToPixel(10f);
protected int mTextColor = Color.BLACK;
  • Description

图表描述字段

Description description=chart.getDescription();
//设置显示位置(unit:px)  默认位置为chart的宽高减去一些偏移量,也就是说不设置这个,默认在右下角
description.setPosition(100,100);
//设置字体大小 最大24,最小6
description.setTextSize(24f);
//设置文本
description.setText("Passion");
//设置字体对齐方式为相对Position左对齐,默认右对齐
description.setTextAlign(Paint.Align.LEFT);
  • LimitLine

限制线,不是所有的chart都支持添加LimitLine。常见支持的有LinChart、BarChart、ScatterChart等。

注意事项:

  • 一条坐标线最多只能添加6个限制线。
  • 限制线并没有限制作用,真正的限制在于你对数据的处理。
  • 添加到某个坐标线上的限制线,和他是垂直的。

示例#创建一个告警线,设置不遮盖数据,添加到左边的y轴。

//创建一个告警线(位置在坐标轴150f值上,标签名llYAxis)
LimitLine llYAxis = new LimitLine(150f, "llYAxis");
//设置线宽(unit dp) 最小0.2,最大12
llYAxis.setLineWidth(4f);
//设置允许虚线,lineLength、spaceLength、phase
llYAxis.enableDashedLine(10f, 10f, 0f);
//设置标签名显示位置
//llYAxis.setLabelPosition(LimitLabelPosition.RIGHT_TOP);
//设置字体大小(unit:dp)
//llYAxis.setTextSize(10f);
//设置字体样式 Typeface tf=Typeface.createFromAsset(getAssets(), "lqh_kai.ttf");
llYAxis.setTypeface(tf);//设置不遮挡数据
YAxis yAxisLeft = chart.getAxisLeft();
yAxisLeft.setDrawLimitLinesBehindData(true);//添加告警线
yAxisLeft.addLimitLine(llYAxis);
  • Legend

注意事项:只有给chart设置数据,图例的设置才有用。

图例设置示例

Legend l = chart.getLegend();
//设置格式为线性
l.setForm(LegendForm.LINE);
//设置字体样式(tf为字体样式,一般来从于assets文件ttf文件。)
//Typeface tf=Typeface.createFromAsset(getAssets(), "lqh_kai.ttf");
l.setTypeface(tf);
//设置字体大小 单位是dp
l.setTextSize(11f);
//设置字体颜色
l.setTextColor(Color.BLACK);//设置位置在底部
l.setVerticalAlignment(Legend.LegendVerticalAlignment.BOTTOM);
//设置位置在最左边
l.setHorizontalAlignment(Legend.LegendHorizontalAlignment.LEFT);
//设置图例方向为水平
l.setOrientation(Legend.LegendOrientation.HORIZONTAL);
//设置图例是在图表内部绘制
l.setDrawInside(true);
//图例默认x、y方向偏移量为5dp
//设置图例Y轴偏移量 (unit:dp)
l.setYOffset(8f);
//设置图例X轴偏移量 (unit:dp)
l.setXOffset(16f);

设置自定义图例

在BarChart里,自动生成的图例的数量和BarDataSet的数量有关。但是一般的场景是只有一组数据,那怎么样显示图例呢,总不能创建N个BarDataSet,每个数据集只放一个数据点吧。那还不如自定义,使用LegendEntry 。
来段伪代码

LegendEntry legendEntryA = new LegendEntry();
legendEntryA.label = "labelName-A";
legendEntryA.formColor = Color.GREEN;

然后通过setCustom(List entries)方法设置即可。

设置图例自动换行

Legend类里面有一个参数mWordWrapEnabled,默认是false,意思是是否要自动换行。
使用下面setWordWrapEnabled方法即可打开自动换行,但是要注意不支持所有类型图例。我愣是没看懂:this is currently supported only for:BelowChartLeft, BelowChartRight, BelowChartCenter。可以实践一下,如果不能满足要求,还是拉源码去改吧。

 /*** Should the legend word wrap? / this is currently supported only for:* BelowChartLeft, BelowChartRight, BelowChartCenter. / note that word* wrapping a legend takes a toll on performance. / you may want to set* maxSizePercent when word wrapping, to set the point where the text wraps.* / default: false** @param enabled*/public void setWordWrapEnabled(boolean enabled) {mWordWrapEnabled = enabled;}

示例

Legend l = chart.getLegend();
l.setWordWrapEnabled(true);
//图例占据整个chart view的最大百分比,通常用来控制换行(default: 0.95f (95%))
l.setMaxSizePercent(0.95f);

  • AxisBase

坐标线,比较常见的XAxis和YAxis都继承自他。

示例-设置X轴

//设置不显示x轴线  默认显示
xAxis.setDrawAxisLine(false);
//设置x轴线的颜色 默认灰色
xAxis.setAxisLineColor(Color.DKGRAY);
//设置不从x轴绘制网格线  默认绘制
xAxis.setDrawGridLines(false);
xAxis.enableGridDashedLine(10f, 10f, 0f);
//设置x方向网格线的颜色 默认灰色
xAxis.setGridColor(Color.LTGRAY);
//设置x轴数据标签相对图表的位置  默认TOP
xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
//设置x轴最大值,不设置也会根据数据集计算出
//常用于数据量较多时,限制一屏幕显示的量
xAxis.setAxisMaximum(1000f);
//设置x轴最小值,不设置也会根据数据集计算出
xAxis.setAxisMinimum(200f);
//设置x轴文字的大小
xAxis.setTextSize(12f);
//设置x轴数据偏移量
xAxis.setYOffset(10f);
//设置x轴标签数组格式处理器   ValueFormatter和IndexAxisValueFormatter都行,重写getFormattedValue返回你想要的
// 如不不设置,默认使用DefaultAxisValueFormatter,DecimalFormat格式化数据,格式"###,###,###,##0"
xAxis.setValueFormatter(new IndexAxisValueFormatter(){@Overridepublic String getFormattedValue(float value) {return super.getFormattedValue(value);}
});
//设置x轴文字颜色
xAxis.setTextColor(Color.RED);
//设置x轴最小刻度 interval  默认1
xAxis.setGranularity(0.01f);

示例-设置Y轴

YAxis yAxis = chart.getAxisLeft();yAxis.setAxisMaximum(200f);
//一般情况都要设置 比如常见的yAxis.setAxisMinimum(0f);不设置可能出现柱子和x轴有偏移量
yAxis.setAxisMinimum(-50f);
//设置不显示此轴
yAxis.setDrawAxisLine(false);
//设置不显示右边的y轴
chart.getAxisRight().setEnabled(false);
//设置y轴数据标签相对图表的位置 默认在图表外面
yAxis.setPosition(YAxis.YAxisLabelPosition.OUTSIDE_CHART);
//设置显示y轴零坐标线   设置后零坐标线会绘制成实线
yAxis.setDrawZeroLine(true);
//设置y轴的文字颜色
yAxis.setTextColor(Color.GREEN);
//设置y轴文字的大小
yAxis.setTextSize(12f);
//设置y轴数据偏移量
yAxis.setXOffset(16f);
//设置y轴label数量,并强制为5个(isforce=true时,会根据数据计算label上的数值)
yAxis.setLabelCount(5, true);
//设置y轴的最小刻度
yAxis.setGranularity(5);

MarkerView

可以理解为数据点的弹出框。

  1. 继承MarkerView 实现一个自定义View
  2. 将chart和markerview绑定起来

示例

  1. 布局
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="wrap_content"android:layout_height="40dp"app:cardBackgroundColor="@android:color/holo_orange_light"xmlns:app="http://schemas.android.com/apk/res-auto"app:cardCornerRadius="4dp"tools:ignore="Overdraw"><TextViewandroid:id="@+id/tvContent"android:layout_width="wrap_content"android:layout_height="match_parent"android:layout_marginLeft="16dp"android:layout_marginRight="16dp"android:layout_marginTop="8dp"android:layout_marginBottom="8dp"android:gravity="center_vertical"android:text=""android:textSize="12sp"android:textColor="@android:color/black"android:ellipsize="end"android:singleLine="true"android:textAppearance="?android:attr/textAppearanceSmall" /></androidx.cardview.widget.CardView>
  1. 自定义MarkerView
@SuppressLint("ViewConstructor")
public class MyMarkerView extends MarkerView {private final TextView tvContent;public MyMarkerView(Context context, int layoutResource) {super(context, layoutResource);tvContent = findViewById(R.id.tvContent);}@Overridepublic void refreshContent(Entry e, Highlight highlight) {//每个点都有一个水表信息,通过Entry获取WaterInfo waterInfo=(WaterInfo)e.getData();if (waterInfo!=null){tvContent.setText(e.getData().toString());}super.refreshContent(e, highlight);}@Overridepublic MPPointF getOffset() {return new MPPointF(-(getWidth() / 2), -getHeight());}
}
  1. 最后设置一下
MyMarkerView mv = new MyMarkerView(this, R.layout.custom_marker_view);
mv.setChartView(chart);
chart.setMarker(mv);

值得注意,以下设置可能造成MarkerView不显示

  • 禁用了每次点击突出显示条目的功能
chart.setHighlightPerTapEnabled(false);
  • ChartData设置禁用数据对象突出显示值
ChartData#setHighlightEnabled(false);

如果只想突出显示部分值,可以通过chart.highlightValue(…)手动设置

补充:使用SpannableStringBuilder显示不一样的字体

public class MyMarkerXyView extends MarkerView {private final TextView tvContent;public MyMarkerXyView(Context context, int layoutResource) {super(context, layoutResource);tvContent = findViewById(R.id.tvContent);}@Overridepublic void refreshContent(Entry e, Highlight highlight) {ForegroundColorSpan colorSpanX = new ForegroundColorSpan(Color.RED);ForegroundColorSpan colorSpanY = new ForegroundColorSpan(Color.BLUE);SpannableStringBuilder ssbBuilder = new SpannableStringBuilder();ssbBuilder.append("●");ssbBuilder.setSpan(colorSpanX, 0, 1, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);ssbBuilder.append("X值:").append(String.valueOf(e.getX()));ssbBuilder.append("\n");int start = ssbBuilder.length();ssbBuilder.append("●");ssbBuilder.setSpan(colorSpanY, start, start + 1, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);ssbBuilder.append("Y值:").append(String.valueOf(e.getY()));tvContent.setText(ssbBuilder);super.refreshContent(e, highlight);}@Overridepublic MPPointF getOffset() {return new MPPointF(-(getWidth() / 2), -getHeight());}
}

问题记录

问题1:无法在MPAndroidChart中设置Double值

不同于IOS版的此库。Android端中有些库(例如android.graphics.matrix)不支持double,这非常不幸。
我在使用3.1.0版的MPAndroidChart,Entry(x,y)都是float作为参数,对于较大和较长的数据,会出现精度的丢失。

举个例子,使用时间戳作为横轴,因为库中api方法都是传float类型的值,而float能保证精度有限(非指数部分只能容纳23位信息,仅使用整数,就会开始看到超过16777216的精度损失)。所以使用时间戳作为坐标的值,会有误差,并且以轴的值作为参考设置的宽度等都会出现问题,如坐标显示与实际相差几十秒、图发生偏移等。如图所示:

问题2:ValueFormatter处出错ArrayIndexOutOfBoundsException

常见于只有一条数据的时候,会出现比如-1这样的value,需要处理

//list是接口获取的数据bean列表for (i in list.indices) {values.add(Entry(i.toFloat(), list[i].number.toFloat(), null))}
chart.xAxis.valueFormatter = object : ValueFormatter() {override fun getFormattedValue(value: Float): String {if (value.toInt() < 0 || value.toInt() >= list.size) {return ""}//显示这条数据的时间字段return list[value.toInt()].dataTime}
}

AAChart

这个库也很好用:AAChartCore-Kotlin,做柱状图、玫瑰图啥的。

后话

如果图表不显示,手动validate一下,还不显示,查数据源和设置的问题。

MPAndroidChart使用记录相关推荐

  1. 关于MPAndroidChart BarChart 柱状图组遇到的一些问题记录。

    关于MPAndroidChart BarChart 柱状图组遇到的一些问题记录. 先上效果图 我用的版本是3.0.2 compile 'com.github.PhilJay:MPAndroidChar ...

  2. MPAndroidChart代码套路记录

    代码套路: 1.Entry键值对,表示每一对值,如果是柱状图就是一根柱子x,y: 2.然后list包装. 3.dataset表示一堆数据,比如折线图就是表示一条线 4.然后list包装 5.放入dat ...

  3. MPAndroidChart LineChart 折线图 你要的都在这里了

    前言   MPAndroidChart已经出了很长的一段时间,相信大家也有所耳闻,自己也使用了有一段时间,固在此写下文章,根据项目的需求,记录一些见解与问题,作为参考.望大家取其精华去其糟粕. 最终效 ...

  4. 笑谈Android图表-MPAndroidChart

    MPAndroidChart是一款基于Android的开源图表库,MPAndroidChart不仅可以在Android设备上绘制各种统计图表,而且可以对图表进行拖动和缩放操作,应用起来非常灵活.MPA ...

  5. MpAndroidChart Y轴显示整数

    最近写项目,用到了图表控件,也就是MpAndroidChart控件 遇到了一个神奇的问题,也就是MP控件要求Y轴数据必须是float的,那我们就需要自己去转换 转换完毕后,发现显示出来的都是带有.00 ...

  6. MPAndroidChart 饼状图 文字重叠问题完美解决

    MPAndroidChart 饼状图 文字重叠问题 前方高能!!!全是干货!!!话不多说先上图~ 因为要保密的原因,lable名字用*号代替了,不用在意这个 前提 引入 MPAndroidChart ...

  7. MPAndroidChart的详细使用——BarChart条形图组(三)

    记录一下BarChart(条形图)的图组(多条数据)使用! 注:本人使用的版本是MPAndroidChart-v3.0.3(如若版本不同有某些方法更新,可在评论区留言,尽我所能帮你解决!) MPAnd ...

  8. MPAndroidChart的详细使用——BarChart条形图(二)

    今天来记录一下BarChart(条形图)的详细使用(美化)! 注:本人使用的版本是MPAndroidChart-v3.0.3(如若版本不同有某些方法更新,可在评论区留言,尽我所能帮你解决!) MPAn ...

  9. MPAndroidChart的详细使用——BarChart叠状条形图(四)

    记录一下BarChart(条形图)的叠状图的使用! 注:本人使用的版本是MPAndroidChart-v3.0.3(如若版本不同有某些方法更新,可在评论区留言,尽我所能帮你解决!) MPAndroid ...

最新文章

  1. 第十六届智能车竞赛线上全国总决赛远程组委会监督腾讯会议
  2. MOSS 2007 EventHandler 开发步骤
  3. EF里的默认映射以及如何使用Data Annotations和Fluent API配置数据库的映射
  4. 从GWT开发人员的角度概述Scala.js
  5. lambda表达式创建一条最简单的线程
  6. mysql宏参数_C语言带参数的宏定义
  7. 12如何隐藏dock栏_ iOS 13 隐藏 Dock栏,一张神奇壁纸就可以
  8. android 传感器学习笔记 一
  9. 360路由器c301最新固件支持万能中继
  10. Win7+Ubuntu双系统时间不一致
  11. 大学生创业如何选择一个不错的创业新项目?
  12. Javashop 7.0 统一登录unionID问题修改
  13. 路由器装mentohust插件破解锐捷认证(Pandorabox固件)
  14. 自我成长的9个小贴士
  15. 【论文】caj文件打开方式
  16. 信号系统matlab实例3——卷积的matlab求解
  17. html 整体缩小zoom,页面缩放兼容性处理方法(zoom,Firefox火狐浏览器)
  18. 第三章 流程控制语句
  19. LaBSE : Language-agnostic BERT Sentence Embedding
  20. flash Builder eclipse 恢复英文

热门文章

  1. c语言输出一个n行m列的图形
  2. Apache开源列式存储引擎Parquet和ORC比较
  3. JS判断是否为数字或为空
  4. Vue中状态管理——Vuex
  5. NodeMCU文档中文翻译 7 DHT温湿度传感器模块
  6. 智能摄像头:下一个战场?
  7. 基于java+springboot+mybatis+vue+elementui的健身房课程预约管理系统
  8. Mac系统下安装RDM
  9. 【PHP】preg_match函数
  10. Python之plot()与Tk窗体的绑定