MPAndroidChart项目实战(三)——饼状图实现和文字重
我的CSDN: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();
}
总结:1.不敢不会修改开源源码的主要原因在于阅读源码能力不够
2.对于动画绘图部分基本看不懂,继续加强
3.像大神这样对开源代码做整理,封装好便于使用,这种封装优化思想需要学习
好了,就写到这里,如果给你带来帮助,记得关注一下博主哦!