本文出自:http://blog.csdn.net/dt235201314/article/details/70142117
源码下载(UpDating 欢迎Star):
https://github.com/JinBoy23520/MPAndroidChartDemoByJin
一丶概述
上一篇代码补了这么久,不好意思,今天再说说MPAndroidChart实现饼状图以及文字冲突问题解决。
二丶演示效果
三丶实现功能
1.饼状图实现
2.解决当占比过小,文字重合问题
四丶看代码
与上一篇,提高代码复用率
PieChartEntity.Java 设置基本属性(这里不做详细说明,百度有文章可查看属性)
/** * 饼状图 * Created by jin */ public class PieChartEntity { private PieChart mChart; private List<PieEntry> mEntries; private String[] labels; private int[] mPieColors; private int mValueColor; private float mTextSize; private PieDataSet.ValuePosition mValuePosition; public PieChartEntity(PieChart chart, List<PieEntry> entries, String[] labels, int []chartColor, float textSize, int valueColor, PieDataSet.ValuePosition valuePosition) { this.mChart = chart; this.mEntries = entries; this.labels= labels; this.mPieColors = chartColor; this.mTextSize= textSize; this.mValueColor = valueColor; this.mValuePosition = valuePosition; initPieChart(); } public PieChartEntity(PieChart chart, List<PieEntry> entries, String[] labels, int []chartColor, float textSize, int valueColor) { this(chart, entries, labels, chartColor, textSize, valueColor, PieDataSet.ValuePosition.INSIDE_SLICE); } private void initPieChart() { mChart.setExtraOffsets(5, 10, 5, 5); mChart.setDragDecelerationFrictionCoef(0.95f); mChart.setDrawCenterText(false); mChart.getDescription().setEnabled(false); mChart.setRotationAngle(0); // enable rotation of the chart by touch mChart.setRotationEnabled(true); mChart.setHighlightPerTapEnabled(true); mChart.setDrawEntryLabels(true); setChartData(); mChart.animateY(1000, Easing.EasingOption.EaseInOutQuad); Legend l = mChart.getLegend(); l.setVerticalAlignment(Legend.LegendVerticalAlignment.TOP); l.setHorizontalAlignment(Legend.LegendHorizontalAlignment.LEFT); l.setOrientation(Legend.LegendOrientation.VERTICAL); l.setDrawInside(false); l.setXEntrySpace(7f); l.setYEntrySpace(1f); l.setYOffset(0f); // entry label styling mChart.setEntryLabelColor(mValueColor); mChart.setEntryLabelTextSize(mTextSize); mChart.setExtraOffsets(10, 10, 10, 10); } public void setHoleDisenabled () { mChart.setDrawHoleEnabled(false); } /** * 中心圆是否可见 * @param holeColor 中心圆颜色 * @param holeRadius 半径 * @param transColor 透明圆颜色 * @param transRadius 透明圆半径 */ public void setHoleEnabled (int holeColor, float holeRadius, int transColor, float transRadius) { mChart.setDrawHoleEnabled(true); mChart.setHoleColor(holeColor); mChart.setTransparentCircleColor(transColor); mChart.setTransparentCircleAlpha(110); mChart.setHoleRadius(holeRadius); mChart.setTransparentCircleRadius(transRadius); } private void setChartData() { PieDataSet dataSet = new PieDataSet(mEntries, ""); dataSet.setSliceSpace(0f); dataSet.setSelectionShift(5f); // dataSet.setEntryLabelsColor(mValueColor); dataSet.setColors(mPieColors); //dataSet.setSelectionShift(0f); dataSet.setYValuePosition(mValuePosition); dataSet.setXValuePosition(mValuePosition); dataSet.setValueLineColor(mValueColor); dataSet.setSelectionShift(15f); dataSet.setValueLinePart1Length(0.6f); dataSet.setValueLineColor(mValueColor); PieData data = new PieData(dataSet); data.setValueFormatter(new PercentFormatter()); data.setValueTextSize(mTextSize); data.setValueTextColor(mValueColor); data.setValueTextColor(mValueColor); mChart.setData(data); // undo all highlights mChart.highlightValues(null); mChart.invalidate(); } /** * <p>说明文字是否可见</p> * @param enabled true 可见,默认可见 */ public void setLegendEnabled(boolean enabled) { mChart.getLegend().setEnabled(enabled); mChart.invalidate(); } public void setPercentValues (boolean showPercent) { mChart.setUsePercentValues(showPercent); } }
这样字可以直接运用了
/** * 添加数据均匀饼装图 */ public void updatePieChart() { int[] colors = {Color.parseColor("#faa74c"), Color.parseColor("#58D4C5"), Color.parseColor("#36a3eb"), Color.parseColor("#cc435f"), Color.parseColor("#f1ea56"), Color.parseColor("#f49468"), Color.parseColor("#d5932c"), Color.parseColor("#34b5cc"), Color.parseColor("#8169c6"), Color.parseColor("#ca4561"),Color.parseColor("#fee335")}; ArrayList<PieEntry> entries = new ArrayList<PieEntry>(); for(int i = 0 ;i <= 5; i++){ PieEntry pieEntry = new PieEntry(60,"项目" + i + "占比"); entries.add(pieEntry); } for(int i = 6 ;i <= 7; i++){ PieEntry pieEntry = new PieEntry(100,"项目" + i + "占比"); entries.add(pieEntry); } PieEntry pieEntry = new PieEntry(100,"项目8占比"); entries.add(pieEntry); if (entries.size() != 0) { PieChart new_pie_chart = (PieChart) mView.findViewById(R.id.new_pie_chart); PieChartEntity pieChartEntity = new PieChartEntity(new_pie_chart, entries, new String[]{"", "", ""}, colors, 12f, Color.GRAY, PieDataSet.ValuePosition.OUTSIDE_SLICE); pieChartEntity.setHoleEnabled(Color.TRANSPARENT, 40f, Color.TRANSPARENT, 40f); pieChartEntity.setLegendEnabled(false); pieChartEntity.setPercentValues(true); } }
运行方法就能实现动态图中数据正常的饼状图
但当数据过小,并且连在一起是就有文字重合的问题
这个时候问题就来了。
解决方案,产品决定占比小于5%或者10%不显示,或另外注明显示。
这下初级程序员就GG了,找不到满足需求的控件Demo参考啊,自定义又写不出来,这时大神微微一笑:加个参数判断一下不就OK啦
思路:三方库的默认PieEntry(float value, String lable),我加个构造方法,加个参数PieEntry(float value, String lable, boolean display)用来判断传的value是否满足要求,然后通过boolean display,同时控制绘图部分,当display为false,我就不花向外线和文字。
先看改造后的PieEntry.Java(修改位置有注释)
public class PieEntry extends Entry { private String label; /** * 用来标记是否显示描述文字 */ private boolean display = true; public PieEntry(float value) { super(0f, value); } public PieEntry(float value, Object data) { super(0f, value, data); } public PieEntry(float value, String label) { super(0f, value); this.label = label; } public PieEntry(float value, String label, Object data) { super(0f, value, data); this.label = label; } /** * 当传数据过小,调用此方法不显示文字 * @param value * @param label * @param display */ public PieEntry(float value ,String label,boolean display){ super(0f,value); this.label = label; this.display = display; } /** * This is the same as getY(). Returns the value of the PieEntry. * * @return */ public float getValue() { return getY(); } public String getLabel() { return label; } /** * 文字绘制时用到做判断 * @return */ public boolean isDisplay() { return display; } public void setLabel(String label) { this.label = label; } /** * 设置display值,达到控制是否显示文字 * @param display */ public void setDisplay(boolean display) { this.display = display; } @Deprecated @Override public void setX(float x) { super.setX(x); Log.i("DEPRECATED", "Pie entries do not have x values"); } @Deprecated @Override public float getX() { Log.i("DEPRECATED", "Pie entries do not have x values"); return super.getX(); } public PieEntry copy() { PieEntry e = new PieEntry(getY(), label, getData()); return e; } }
再看关于绘图的类PieChartRenderer.Java
这个类太长,主要修改方法是drawValues (修改位置有注释)
@Override public void drawValues(Canvas c) { MPPointF center = mChart.getCenterCircleBox(); // get whole the radius float 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 holeRadiusPercent = mChart.getHoleRadius() / 100.f; float labelRadiusOffset = radius / 10f * 3.6f; if (mChart.isDrawHoleEnabled()) { labelRadiusOffset = (radius - (radius * holeRadiusPercent)) / 2f; } 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 = 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 DataSet applyValueTextStyle(dataSet); float lineHeight = Utils.calcTextHeight(mValuePaint, "Q") + Utils.convertDpToPixel(4f); IValueFormatter formatter = dataSet.getValueFormatter(); int entryCount = dataSet.getEntryCount(); mValueLinePaint.setColor(dataSet.getValueLineColor()); mValueLinePaint.setStrokeWidth(Utils.convertDpToPixel(dataSet.getValueLineWidth())); final float sliceSpace = getSliceSpace(dataSet); for (int j = 0; j < entryCount; j++) { PieEntry entry = dataSet.getEntryForIndex(j); if (xIndex == 0) angle = 0.f; else angle = absoluteAngles[xIndex - 1] * phaseX; final float sliceAngle = drawAngles[xIndex]; final float sliceSpaceMiddleAngle = sliceSpace / (Utils.FDEG2RAD * labelRadius); // offset needed to center the drawn text in the slice final 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(); final float sliceXBase = (float) Math.cos(transformedAngle * Utils.FDEG2RAD); final float sliceYBase = (float) Math.sin(transformedAngle * 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); else line1Radius = radius * valueLinePart1OffsetPercentage; final float polyline2Width = dataSet.isValueLineVariableLength() ? labelRadius * valueLineLength2 * (float) Math.abs(Math.sin( transformedAngle * Utils.FDEG2RAD)) : labelRadius * valueLineLength2; final float pt0x = line1Radius * sliceXBase + center.x; final float pt0y = line1Radius * sliceYBase + center.y; final float pt1x = labelRadius * (1 + valueLineLength1) * sliceXBase + center.x; final float pt1y = labelRadius * (1 + valueLineLength1) * sliceYBase + center.y; if (transformedAngle % 360.0 >= 90.0 && transformedAngle % 360.0 <= 270.0) { pt2x = pt1x - polyline2Width; pt2y = pt1y; mValuePaint.setTextAlign(Align.RIGHT); if(drawXOutside) mEntryLabelsPaint.setTextAlign(Align.RIGHT); labelPtx = pt2x - offset; labelPty = pt2y; } else { pt2x = pt1x + polyline2Width; pt2y = pt1y; mValuePaint.setTextAlign(Align.LEFT); if(drawXOutside) mEntryLabelsPaint.setTextAlign(Align.LEFT); labelPtx = pt2x + offset; labelPty = pt2y; } /** * 这里是绘制圈外线所以须添加 */ if (entry.isDisplay()) { if (dataSet.getValueLineColor() != ColorTemplate.COLOR_NONE) { c.drawLine(pt0x, pt0y, pt1x, pt1y, mValueLinePaint); c.drawLine(pt1x, pt1y, pt2x, pt2y, mValueLinePaint); } } /** * 这里也相关 */ // draw everything, depending on settings if (drawXOutside && drawYOutside&&entry.isDisplay()) { drawValue(c, formatter, value, entry, 0, labelPtx, labelPty, dataSet.getValueTextColor(j)); if (j < data.getEntryCount() && entry.getLabel() != null) { drawEntryLabel(c, entry.getLabel(), labelPtx, labelPty + lineHeight); } } else if (drawXOutside) { /** * 一样相关 */ if (j < data.getEntryCount() && entry.getLabel() != null&&entry.isDisplay()) { drawEntryLabel(c, entry.getLabel(), labelPtx, labelPty + lineHeight / 2.f); } } else if (drawYOutside) { drawValue(c, formatter, value, entry, 0, labelPtx, labelPty + lineHeight / 2.f, dataSet .getValueTextColor(j)); } } if (drawXInside || drawYInside) { // calculate the text position float x = labelRadius * sliceXBase + center.x; float y = labelRadius * sliceYBase + center.y; mValuePaint.setTextAlign(Align.CENTER); // draw everything, depending on settings if (drawXInside && drawYInside&&entry.isDisplay()) { drawValue(c, formatter, value, entry, 0, x, y, dataSet.getValueTextColor(j)); if (j < data.getEntryCount() && entry.getLabel() != null) { drawEntryLabel(c, entry.getLabel(), x, y + lineHeight); } } else if (drawXInside) { if (j < data.getEntryCount() && entry.getLabel() != null) { drawEntryLabel(c, entry.getLabel(), x, y + lineHeight / 2f); } } else if (drawYInside) { drawValue(c, formatter, value, entry, 0, x, y + lineHeight / 2f, dataSet.getValueTextColor(j)); } } xIndex++; } } MPPointF.recycleInstance(center); c.restore(); }
好了,就写到这里,如果给你带来帮助,记得关注一下博主哦!