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

来源:互联网 发布:淘宝网软件免费下载 编辑:程序博客网 时间:2024/06/12 00:03

本文出自:http://blog.csdn.net/dt235201314/article/details/70142117

源码下载(UpDating 欢迎Star):

https://github.com/JinBoy23520/MPAndroidChartDemoByJin

MPAndroidChart常见设置属性(一)——应用层 

MPAndroidChart项目实战(一)——实现对比性柱状图 

MPAndroidChart项目实战(二)——双平滑曲线(双折线图)和MarkView实现 

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

MPAndroidChart项目实战(四)——柱状图实现及X轴文字不显示问题和柱状图上显示文字 

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 (修改位置有注释)

@Overridepublic 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.像大神这样对开源代码做整理,封装好便于使用,这种封装优化思想需要学习

好了,就写到这里,如果给你带来帮助,记得关注一下博主哦!


3 3