您的位置:首页 > 移动开发 > Android开发

MPAndroidChart项目实战(三)——饼状图实现和文字重合问题解决

2017-04-12 15:45 495 查看
本文出自:http://blog.csdn.net/dt235201314/article/details/70142117

源码下载(UpDating 欢迎Star):

https://github.com/JinBoy23520/MPAndroidChartDemoByJin



MPAndroidChart常见设置属性(一)——应用层 
MPAndroidChart项目实战(一)——实现对比性柱状图 
MPAndroidChart项目实战(二)——双平滑曲线(双折线图)和MarkView实现 
MPAndroidChart项目实战(三)——饼状图实现和文字重合问题解决 
MPAndroidChart项目实战(四)——柱状图实现及X轴文字不显示问题和柱状图上显示文字 
MPAndroidChart X轴文字斜着显示 
MPAndroidChart项目实战(五)——组合图实现趋势图 
MPAndroidChart项目实战(六)——自定义1MPAndroidChart滑动冲突解决(搞不定产品设计师就只能搞自己) 
MPAndroidChart项目实战(七)——自定义横向柱状图 
MPAndroidChart项目实战(八)——自定义分段堆积柱状图 
MPAndroidChart项目实战(九)——自定义带文字分段堆积柱状图 


一丶概述

上一篇代码补了这么久,不好意思,今天再说说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.像大神这样对开源代码做整理,封装好便于使用,这种封装优化思想需要学习

好了,就写到这里,如果给你带来帮助,记得关注一下博主哦!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐