MPAndroidChart 饼状图 文字重叠问题

前方高能!!!全是干货!!!话不多说先上图~

因为要保密的原因,lable名字用*号代替了,不用在意这个

前提

引入 MPAndroidChart 依赖

implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0'

解决思路

1.文字显示重叠有一部分原因是因为数据过多,所以我把值为0的数据过滤掉不显示了,当然,这个需要 在产品允许的情况下才可以。

2.如图,将lable显示在饼图外部

3.PieChartRenderer 这个类是绘制线条的,我们要做的就是重写这个类,然后重写PieChart类引用我们重写后的PieChartRenderer

4.PieChartRenderer 重写思路:记录已经绘制过的Y坐标,然后判断剩下的位置能否显示的下一条lable,显示不下的话要就需要挪位置

5.网上找了很多解决方式,都存在瑕疵,所以决定自己动手撸

具体实现

1.将lable显示在饼图外部

代码如下:

PieDataSet dataSet = new PieDataSet(entries, "");
dataSet.setYValuePosition(PieDataSet.ValuePosition.OUTSIDE_SLICE);//value外部展示

2.重写PieChartRenderer

代码如下:

public class PieChartCustomRendederer extends PieChartRenderer {private Paint mEntryLabelsPaint=new Paint();public PieChartCustomRendederer(PieChart chart, ChartAnimator animator, ViewPortHandler viewPortHandler) {super(chart, animator, viewPortHandler);}private float[] minData(float leftRecordY[][], float pt1y) {//计算出离的最近的List<Float> bigD = new ArrayList<>();//变换前的数据List<Float> nearestlist = new ArrayList<>();//变换后的数据List<Float> nearestlistCopy = new ArrayList<>();for (int k = 0; k < leftRecordY[0].length; k++) {if (leftRecordY[0][k] != 0) {bigD.add(Math.abs(leftRecordY[0][k] - pt1y));nearestlist.add(leftRecordY[0][k]);nearestlistCopy.add(leftRecordY[1][k]);}}// 距离最近的点,数值float[] rF = new float[2];if (bigD.size() == 0) {return rF;}float minD = bigD.get(0);rF[0]= nearestlist.get(0);rF[1]= nearestlistCopy.get(0);for (int g = 0; g < bigD.size(); g++) {if (bigD.get(g) < minD) {minD = bigD.get(g);rF[0]= nearestlist.get(g);rF[1]= nearestlistCopy.get(g);}}return rF;}private String text = "2.0%";@Overridepublic void drawValues(Canvas c) {MPPointF center = mChart.getCenterCircleBox();// get whole the radiusfloat radius = mChart.getRadius();float rotationAngle = mChart.getRotationAngle();float[] drawAngles = mChart.getDrawAngles();float[] absoluteAngles = mChart.getAbsoluteAngles();float phaseX = mAnimator.getPhaseX();float phaseY = mAnimator.getPhaseY();final float roundedRadius = (radius - (radius * mChart.getHoleRadius() / 100f)) / 2f;final float holeRadiusPercent = mChart.getHoleRadius() / 100.f;float labelRadiusOffset = radius / 10f * 3.6f;if (mChart.isDrawHoleEnabled()) {labelRadiusOffset = (radius - (radius * holeRadiusPercent)) / 2f;if (!mChart.isDrawSlicesUnderHoleEnabled() && mChart.isDrawRoundedSlicesEnabled()) {// Add curved circle slice and spacing to rotation angle, so that it sits nicely insiderotationAngle += roundedRadius * 360 / (Math.PI * 2 * radius);}}final float labelRadius = radius - labelRadiusOffset;PieData data = mChart.getData();List<IPieDataSet> dataSets = data.getDataSets();float yValueSum = data.getYValueSum();boolean drawEntryLabels = mChart.isDrawEntryLabelsEnabled();float angle;int xIndex = 0;c.save();float offset = com.github.mikephil.charting.utils.Utils.convertDpToPixel(5.f);for (int i = 0; i < dataSets.size(); i++) {IPieDataSet dataSet = dataSets.get(i);final boolean drawValues = dataSet.isDrawValuesEnabled();if (!drawValues && !drawEntryLabels)continue;final PieDataSet.ValuePosition xValuePosition = dataSet.getXValuePosition();final PieDataSet.ValuePosition yValuePosition = dataSet.getYValuePosition();// apply the text-styling defined by the DataSetapplyValueTextStyle(dataSet);Rect rect = new Rect();mValuePaint.getTextBounds(text, 0, text.length(), rect);mValuePaint.setColor(dataSet.getColor(i));int textHeight = (int) (rect.height() * 1.4f);//文本的高度float lineHeight =  Utils.calcTextHeight(mValuePaint, "Q") + Utils.convertDpToPixel(4f);ValueFormatter formatter = dataSet.getValueFormatter();int entryCount = dataSet.getEntryCount();mValueLinePaint.setColor(dataSet.getValueLineColor());mValueLinePaint.setStrokeWidth(com.github.mikephil.charting.utils.Utils.convertDpToPixel(dataSet.getValueLineWidth()));final float sliceSpace = getSliceSpace(dataSet);MPPointF iconsOffset = MPPointF.getInstance(dataSet.getIconsOffset());iconsOffset.x = com.github.mikephil.charting.utils.Utils.convertDpToPixel(iconsOffset.x);iconsOffset.y = com.github.mikephil.charting.utils.Utils.convertDpToPixel(iconsOffset.y);//第一个存以前的,第二个存变换位置后的float leftRecordY[][] = new float[2][entryCount];float rightRecordY[][] = new float[2][entryCount];for (int j = 0; j < entryCount; j++) {PieEntry entry = dataSet.getEntryForIndex(j);if (xIndex == 0)angle = 0.f;elseangle = absoluteAngles[xIndex - 1] * phaseX;final float sliceAngle = drawAngles[xIndex];final float sliceSpaceMiddleAngle = sliceSpace / (com.github.mikephil.charting.utils.Utils.FDEG2RAD * labelRadius);// offset needed to center the drawn text in the slicefinal float angleOffset = (sliceAngle - sliceSpaceMiddleAngle / 2.f) / 2.f;angle = angle + angleOffset;final float transformedAngle = rotationAngle + angle * phaseY;float value = mChart.isUsePercentValuesEnabled() ? entry.getY()/ yValueSum * 100f : entry.getY();String formattedValue = formatter.getPieLabel(value, entry);String entryLabel = entry.getLabel();final float sliceXBase = (float) Math.cos(transformedAngle * com.github.mikephil.charting.utils.Utils.FDEG2RAD);final float sliceYBase = (float) Math.sin(transformedAngle * com.github.mikephil.charting.utils.Utils.FDEG2RAD);final boolean drawXOutside = drawEntryLabels &&xValuePosition == PieDataSet.ValuePosition.OUTSIDE_SLICE;final boolean drawYOutside = drawValues &&yValuePosition == PieDataSet.ValuePosition.OUTSIDE_SLICE;final boolean drawXInside = drawEntryLabels &&xValuePosition == PieDataSet.ValuePosition.INSIDE_SLICE;final boolean drawYInside = drawValues &&yValuePosition == PieDataSet.ValuePosition.INSIDE_SLICE;if (drawXOutside || drawYOutside) {final float valueLineLength1 = dataSet.getValueLinePart1Length();final float valueLineLength2 = dataSet.getValueLinePart2Length();final float valueLinePart1OffsetPercentage = dataSet.getValueLinePart1OffsetPercentage() / 100.f;float pt2x, pt2y;float labelPtx, labelPty;float line1Radius;if (mChart.isDrawHoleEnabled())line1Radius = (radius - (radius * holeRadiusPercent))* valueLinePart1OffsetPercentage+ (radius * holeRadiusPercent);elseline1Radius = radius * valueLinePart1OffsetPercentage;final float polyline2Width =  dataSet.isValueLineVariableLength()? labelRadius * valueLineLength2 * (float) Math.abs(Math.sin(transformedAngle * Utils.FDEG2RAD)): labelRadius * valueLineLength2;float pt0x = line1Radius * sliceXBase + center.x;float pt0y = line1Radius * sliceYBase + center.y;float pt1x = labelRadius * (1 + valueLineLength1) * sliceXBase + center.x;float pt1y = labelRadius * (1 + valueLineLength1) * sliceYBase + center.y;if (transformedAngle % 360.0 >= 90.0 && transformedAngle % 360.0 <= 270.0) {float nearestPoint[] = minData(leftRecordY, pt1y);leftRecordY[0][j] = pt1y;//判断是否需要挪位置if (nearestPoint[0] != 0 && Math.abs(nearestPoint[0] - pt1y) < (textHeight+lineHeight)) {pt1y = nearestPoint[1] - textHeight;}pt2x = pt1x - polyline2Width;pt2y = pt1y;mValuePaint.setTextAlign(Paint.Align.RIGHT);if(drawXOutside)mEntryLabelsPaint.setTextAlign(Paint.Align.RIGHT);labelPtx = pt2x - offset;labelPty = pt2y;leftRecordY[1][j] = pt1y;} else {float[] nearestPoint = minData(rightRecordY, pt1y);rightRecordY[0][j] = pt1y;//判断是否需要挪位置if (nearestPoint[0] != 0 && Math.abs(nearestPoint[0] - pt1y) < (textHeight+lineHeight)) {pt1y = nearestPoint[1] + textHeight;}pt2x = pt1x + polyline2Width;pt2y = pt1y;mValuePaint.setTextAlign(Paint.Align.LEFT);if(drawXOutside)mEntryLabelsPaint.setTextAlign(Paint.Align.LEFT);labelPtx = pt2x + offset;labelPty = pt2y;rightRecordY[1][j] = labelPty;}if (dataSet.getValueLineColor() != ColorTemplate.COLOR_NONE) {if (dataSet.isUsingSliceColorAsValueLineColor()) {mValueLinePaint.setColor(dataSet.getColor(j));}c.drawLine(pt0x, pt0y, pt1x, pt1y, mValueLinePaint);c.drawLine(pt1x, pt1y, pt2x, pt2y, mValueLinePaint);}// draw everything, depending on settingsif (drawXOutside && drawYOutside) {drawValue(c, formattedValue, labelPtx, labelPty, dataSet.getValueTextColor(j));if (j < data.getEntryCount() && entryLabel != null) {drawEntryLabel(c, entryLabel, labelPtx, labelPty + lineHeight);}} else if (drawXOutside) {if (j < data.getEntryCount() && entryLabel != null) {drawEntryLabel(c, entryLabel, labelPtx, labelPty + lineHeight / 2.f);}} else if (drawYOutside) {drawValue(c, formattedValue, labelPtx, labelPty + lineHeight / 2.f, dataSet.getValueTextColor(j));}}if (drawXInside || drawYInside) {// calculate the text positionfloat x = labelRadius * sliceXBase + center.x;float y = labelRadius * sliceYBase + center.y;mValuePaint.setTextAlign(Paint.Align.CENTER);// draw everything, depending on settingsif (drawXInside && drawYInside) {drawValue(c, formattedValue, x, y, dataSet.getValueTextColor(j));if (j < data.getEntryCount() && entryLabel != null) {drawEntryLabel(c, entryLabel, x, y + lineHeight);}} else if (drawXInside) {if (j < data.getEntryCount() && entryLabel != null) {drawEntryLabel(c, entryLabel, x, y + lineHeight / 2f);}} else if (drawYInside) {drawValue(c, formattedValue, x, y + lineHeight / 2f, dataSet.getValueTextColor(j));}}if (entry.getIcon() != null && dataSet.isDrawIconsEnabled()) {Drawable icon = entry.getIcon();float x = (labelRadius + iconsOffset.y) * sliceXBase + center.x;float y = (labelRadius + iconsOffset.y) * sliceYBase + center.y;y += iconsOffset.x;Utils.drawImage(c,icon,(int)x,(int)y,icon.getIntrinsicWidth(),icon.getIntrinsicHeight());}xIndex++;}MPPointF.recycleInstance(iconsOffset);}MPPointF.recycleInstance(center);c.restore();}
}

3.重写PieChart类引用重写后的PieChartRenderer

public class MyPieChart extends PieChart {public MyPieChart(Context context) {super(context);}public MyPieChart(Context context, AttributeSet attrs) {super(context, attrs);}public MyPieChart(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);}@Overrideprotected void init() {super.init();//此处把mRenderer替换成我们自己的PieChartRenderermRenderer = new PieChartCustomRendederer(this, mAnimator, mViewPortHandler);}
}

4.布局文件直接使用MyPieChart 即可

各种属性设置自行百度,网上有很多

5.关于lable与value在一行显示的实现,我是重写了ValueFormatter

public class MyPercentFormatter extends ValueFormatter {public DecimalFormat mFormat;private PieChart pieChart;public MyPercentFormatter() {mFormat = new DecimalFormat("###,###,##0.0");}// Can be used to remove percent signs if the chart isn't in percent modepublic MyPercentFormatter(PieChart pieChart) {this();this.pieChart = pieChart;}@Overridepublic String getFormattedValue(float value) {return mFormat.format(value) + "%";}@Overridepublic String getPieLabel(float value, PieEntry pieEntry) {if (pieChart != null && pieChart.isUsePercentValuesEnabled()) {// Converted to percentreturn pieEntry.getLabel()+" "+getFormattedValue(value);} else {// raw value, skip percent signreturn mFormat.format(value);}}
}

然后设置ValueFormatter

 @BindView(R.id.pc_hours)MyPieChart pc_hours;PieData data = new PieData(dataSet);data.setValueFormatter(new MyPercentFormatter(pc_hours));

总结

到此,文字重叠的问题已经彻底解决了,你学废了吗
代码可以直接复制过去用,注意依赖引入的版本,版本不一致,代码可能有报错
有问题的同学欢迎留言
关于样式不知道怎么实现的同学也可以留言哦
如果帮到你了,不妨点个赞
参考文献: https://blog.csdn.net/aichu6610/article/details/108278760
实现思路是参考这位老哥的,不过他的代码还是存在个别数据文字重叠的问题

MPAndroidChart 饼状图 文字重叠问题完美解决相关推荐

  1. python饼状图文字重叠_Matplotlib 绘制饼图解决文字重叠的方法

    在使用matplotlib 绘制饼图的时候有些时候一些数据的比列太小在饼图呈现的效果不明显 很容易被覆盖,为了解决这个问题以下就是我个人的心得. [未解决之前呈现的效果] 可以看到这个饼状图其他和硕士 ...

  2. 【eCharts】echarts饼状图数据重叠导致指示线及显示文字重叠解决

    1. 解决前 2.解决后 3.代码 function makePie(id, title, name, data, show) {if (!show) {show = false;}var myCha ...

  3. android 大屏图表 MPAndroidChart 饼状图 饼图,圆形统计图

    //图表库implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0' X轴:XAxis Y轴:YAxis 图例:Legend 描述:Descri ...

  4. H5画布 canvas(一)canvas简介、绘制圆形矩形、案例饼状图绘制

    目录 1. canvas 简介 2. canvas 标签介绍 3. canvas 上下文 Context 4. 案例:在 canvas 画布中绘制表格 5. canvas 的 beginPath 状态 ...

  5. H5画布 canvas(一)canvas简介、绘制圆形/矩形、案例饼状图绘制

    目录 1. canvas 简介 2. canvas 标签介绍 3. canvas 上下文 Context 4. 案例:在 canvas 画布中绘制表格 5. canvas 的 beginPath 状态 ...

  6. echarts饼图文字重叠问题及解决方法

    实现前台样式的时候发现饼状图文字部分重合了 文章目录 前言 1.解决方法 前言 实现前台样式的时候发现饼状图文字部分重合了如下面所示: 找了很多方法以下是个人总结的: 1.解决方法 代码如下,添加no ...

  7. Android之玩转MPAndroidChart让(折线图、柱形图、饼状图、散列图、雷达图)优雅的舞...

    2019独角兽企业重金招聘Python工程师标准>>> 把开源项目MPAndroidChart里面的折线图.柱形图.饼状图.散列图.雷达图怎么使用和一些属性详细的介绍,当我们项目 g ...

  8. MpAndroidChart源码修改之饼状图添加标志线

    由于项目需要,需要改MpandroidChart源码,下面,先看下效果图: 效果图 效果很简单,但是由于所选依赖库没提供相关方法,所以就需要重写源码了. 这条红色的标志线其实就是那个影厅的均值嘛,这条 ...

  9. echarts饼状图隐藏标示线和标示文字

    //在建项目分布饼状图 proHoursPieOption = {title : {// text: '材价来源占比分析', x: 15, y: 15, textStyle:{ //标题文字设置 fo ...

最新文章

  1. LeetCode Search in Rotated Sorted Array II
  2. composer 更新版本
  3. 强软弱虚引用,只有体会过了,才能记住
  4. 10分钟开始.Net Core
  5. oracle查看被锁的行,查找被锁的表到底是哪一行被锁定了
  6. kodi资源_kodi.tv让你从此看4K节目可以更多选择
  7. “有钱人大多不快乐”这种观点,只是普通人的心理安慰吗?
  8. 在springcacheinvokecontext中没找到field_CNN中的感受野
  9. 42步进电机转速力矩曲线_42步进电机转速范围说明(28步进电机转速测试)
  10. 「缠师课后回复精选」第15课:没有趋势,没有背驰。
  11. Variable used in lambda expression should be final or effectively final报错解决方案
  12. 部分手机打开USB调试,安装失败解决办法
  13. 文件上传之500错误
  14. insyde H2OFFT cannot run on battery power
  15. Lr_debug_message,Lr_output_message,Lr_error_message,Lrd_stmt,Lrd_fetch
  16. 课程笔记-三维点云处理01 ——Introduction and Basic Algorithms
  17. Matlab 矩阵元素选取方法
  18. 让你在[三分钟自我介绍]中突出自我
  19. SVN服务端安装与配置
  20. Vue+bpmn.js自定义流程图之palette(二)

热门文章

  1. imagenet分类
  2. 用Windows自带工具给U盘4k对齐
  3. [CryptoHack] ELLIPTIC CURVES-STARTER Write-Up
  4. 异常检测算法:Elliptic Envelope算法的python代码实现
  5. revit卸载/完美解决安装失败/如何彻底卸载清除干净revit各种残留注册表和文件的方法
  6. 数学建模:火箭发生升空模型——基于matlab语言
  7. 项目研发,有哪些好用的免费脑图工具软件
  8. 单片机的程序结束后都干嘛去了?
  9. pdf怎么拆分成几个部分?怎么拆分pdf中的一部分?
  10. Consider the following: If you want an embedded database (H2, HSQL or Derby), please put it on the