MPAndroidChart饼图(PieChart)Value值重叠的解决方法(一)

说明:下文中的bug已经在MPAndroidChart饼图(PieChart)Value值重叠的解决方法(二)中完美解决了,可以去看看。

先看下前后对比的效果图

修改前.jpg
修改后.jpg

背景

项目做完出来的时候,我就发现了这个问题,奈何在网上没找解决办法,而我又是个Android渣渣,本来准备蒙混过关的,可是测试一定要我改,没办法只能看看MPAndroidChart里的可能涉及到的源码,看下能不能改好。所以,如果有不对和优化的地方,希望大家能指出,相互进步。

已知bug

(已经在MPAndroidChart饼图(PieChart)Value值重叠的解决方法(二)中解决了)
PieChart不能设置为可以转动,即pieChart.setRotationEnabled(false);要设置成false,如果转动,会在转动的时候导致值的位置错乱,知道怎么解决的同学请指点,有空我也看看能不能解决。

思路

网上有一个解决方案是,把占比较小部分的值不显示出来,但是博主也说,还是会有重叠的可能,不过大家可以看下地址
我的思路是,每次都记住上一个值Y方向位置,和这次对比,如果间距小于了值字体的高度,则改变本次画值的位置

实现步骤

  • 通过观察原生态的PieChart,发现饼图绘制过程,其实画值的过程是由mRenderer实现的,如下:
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
    
            if (mData == null)
                return;
    
            mRenderer.drawData(canvas);
    
            if (valuesToHighlight())
                mRenderer.drawHighlighted(canvas, mIndicesToHighlight);
    
            mRenderer.drawExtras(canvas);
    
            mRenderer.drawValues(canvas);
    
            mLegendRenderer.renderLegend(canvas);
    
            drawDescription(canvas);
    
            drawMarkers(canvas);
        }

所以,我们只需要修改mRenderer中画图的实现步骤就好了,那我们就需要把这个mRenderer替换成我们自己定义的PieChartRenderer,而mRenderer又是在下面这个方法中初始化的:

    @Override
    protected void init() {
        super.init();

        mRenderer = new PieChartRenderer(this, mAnimator, mViewPortHandler);
        mXAxis = null;

        mHighlighter = new PieHighlighter(this);
    }

因为我没找到可以直接设置mRenderer的方法,所以我们需要自己创建一个PieChart的子类,重写init()方法,让mRenderer变成我们自己的PieChartRenderer。

  • 先创建我们自己的PieChartRenderer吧,创建一个类继承PieChartRenderer,有一个被注释的drawValues(Canvas c)方法是饼图左右两边上边对其,效果可以自己打开试下(因为我感觉遍历了太多次,所以就没有使用),其他的代码中关键部分都有说明,就不细说了,代码如下:
public class MyPieChartRenderer extends PieChartRenderer {
    private static final String TAG = "MyPieChartRenderer";

    public MyPieChartRenderer(PieChart chart, ChartAnimator animator, ViewPortHandler viewPortHandler) {
        super(chart, animator, viewPortHandler);
    }

    String text = "2.0%";

    /**
     * 这个方法,左边是从下往上画,右边是从上往下画
     * @param c
     */
    @Override
    public void drawValues(Canvas c) {

        Rect rect = new Rect();
        getPaintEntryLabels().getTextBounds(text, 0, text.length(), rect);
        int textHeight = rect.height();//文本的高度

        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);

            MPPointF iconsOffset = MPPointF.getInstance(dataSet.getIconsOffset());
            iconsOffset.x = Utils.convertDpToPixel(iconsOffset.x);
            iconsOffset.y = Utils.convertDpToPixel(iconsOffset.y);

            float lastPositionOfLeft = 0;
            float lastPositionOfRight = 0;

            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;

                    //左右算法不一样,左边是从下往上排的,即你可以理解为饼图是顺时针方向,从零点排到12点的360度圆形,建议先看else里的,即右边的,方便理解
                    if (transformedAngle % 360.0 >= 90.0 && transformedAngle % 360.0 <= 270.0) {//左边部分
//                        pt2x = pt1x - polyline2Width;
                        pt2x = center.x - radius - 5;
                        if (lastPositionOfLeft == 0) {//第一个不用管
                            pt2y = pt1y;
                        } else {
                            if (lastPositionOfLeft - pt1y < textHeight) {//如果上一个labley的位置减去计算出的pt1y的位置间距小于lable的高度,则需要在计算出的y基础上加上差的间距
                                pt2y = pt1y - (textHeight - (lastPositionOfLeft - pt1y));//例如:lable高度5,计算出的pt1y位置10,上一个labley的位置12,则间距只有lastPositionOfRight-pt1y=2,还需要减去少的textHeight-(lastPositionOfRight-pt1y)=3才行
                            } else {
                                pt2y = pt1y;
                            }
                        }
                        lastPositionOfLeft = pt2y;//记录上一个lableY方向的位置

                        mValuePaint.setTextAlign(Paint.Align.RIGHT);

                        if (drawXOutside)
                            getPaintEntryLabels().setTextAlign(Paint.Align.RIGHT);

                        labelPtx = pt2x - offset;
                        labelPty = pt2y;
                    } else {//右边部分
//                        pt2x = pt1x + polyline2Width;
                        pt2x = center.x + radius + 5;
                        if (lastPositionOfRight == 0) {//第一个不用管
                            pt2y = pt1y;
                        } else {
                            if (pt1y - lastPositionOfRight < textHeight) {//如果计算出的pt1y的位置减去上一个labley的位置间距小于lable的高度,则需要在计算出的y基础上加上差的间距
                                pt2y = pt1y + (textHeight - (pt1y - lastPositionOfRight));//例如:lable高度5,计算出的pt1y位置10,上一个labley的位置8,则间距只有pt1y-lastPositionOfRight=2,还需要加上少的textHeight-(pt1y-lastPositionOfRight)=3才行
                            } else {
                                pt2y = pt1y;
                            }
                        }
                        lastPositionOfRight = pt2y;//记录上一个lableY方向的位置
                        mValuePaint.setTextAlign(Paint.Align.LEFT);

                        if (drawXOutside)
                            getPaintEntryLabels().setTextAlign(Paint.Align.LEFT);

                        labelPtx = pt2x + offset;
                        labelPty = pt2y;
                    }

                    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) {

                        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) {
                            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(Paint.Align.CENTER);

                    // draw everything, depending on settings
                    if (drawXInside && drawYInside) {

                        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));
                    }
                }

                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();
    }

    /**
     * 这个方法,是两侧都上往下排列,保证上面整齐
     */
//    @Override
//    public void drawValues(Canvas c) {
//
//
//        Rect rect = new Rect();
//        getPaintEntryLabels().getTextBounds(text, 0, text.length(), rect);
//        int textHeight = rect.height();//文本的高度
//
//        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);
//
//            MPPointF iconsOffset = MPPointF.getInstance(dataSet.getIconsOffset());
//            iconsOffset.x = Utils.convertDpToPixel(iconsOffset.x);
//            iconsOffset.y = Utils.convertDpToPixel(iconsOffset.y);
//
//            float lastPositionOfLeft = 0;
//            float lastPositionOfRight = 0;
//
//            //画右边
//            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;
//
//                    //左右算法不一样,左边是从下往上排的,即你可以理解为饼图是顺时针方向,从零点排到12点的360度圆形,建议先看else里的,即右边的,方便理解
//                    if (transformedAngle % 360.0 >= 90.0 && transformedAngle % 360.0 <= 270.0) {//左边部分
////                        pt2x = center.x - radius - 5;
////                        if (lastPositionOfLeft == 0) {//第一个不用管
////                            pt2y = pt1y;
////                        } else {
////                            if (lastPositionOfLeft - pt1y < textHeight) {//如果上一个labley的位置减去计算出的pt1y的位置间距小于lable的高度,则需要在计算出的y基础上加上差的间距
////                                pt2y = pt1y - (textHeight - (lastPositionOfLeft - pt1y));//例如:lable高度5,计算出的pt1y位置10,上一个labley的位置12,则间距只有lastPositionOfRight-pt1y=2,还需要减去少的textHeight-(lastPositionOfRight-pt1y)=3才行
////                            } else {
////                                pt2y = pt1y;
////                            }
////                        }
////                        lastPositionOfLeft = pt2y;//记录上一个lableY方向的位置
////
////                        mValuePaint.setTextAlign(Paint.Align.RIGHT);
////
////                        if (drawXOutside)
////                            getPaintEntryLabels().setTextAlign(Paint.Align.RIGHT);
////
////                        labelPtx = pt2x - offset;
////                        labelPty = pt2y;
//                        break;
//                    } else {//右边部分
////                        pt2x = pt1x + polyline2Width;
//                        pt2x = center.x + radius + 5;
//                        if (lastPositionOfRight == 0) {//第一个不用管
//                            pt2y = pt1y;
//                        } else {
//                            if (pt1y - lastPositionOfRight < textHeight) {//如果计算出的pt1y的位置减去上一个labley的位置间距小于lable的高度,则需要在计算出的y基础上加上差的间距
//                                pt2y = pt1y + (textHeight - (pt1y - lastPositionOfRight));//例如:lable高度5,计算出的pt1y位置10,上一个labley的位置8,则间距只有pt1y-lastPositionOfRight=2,还需要加上少的textHeight-(pt1y-lastPositionOfRight)=3才行
//                            } else {
//                                pt2y = pt1y;
//                            }
//                        }
//                        lastPositionOfRight = pt2y;//记录上一个lableY方向的位置
//                        mValuePaint.setTextAlign(Paint.Align.LEFT);
//
//                        if (drawXOutside)
//                            getPaintEntryLabels().setTextAlign(Paint.Align.LEFT);
//
//                        labelPtx = pt2x + offset;
//                        labelPty = pt2y;
//                    }
//
//                    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) {
//
//                        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) {
//                            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(Paint.Align.CENTER);
//
//                    // draw everything, depending on settings
//                    if (drawXInside && drawYInside) {
//
//                        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));
//                    }
//                }
//
//                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++;
//            }
//
//            //画左边
//            xIndex = entryCount-1;
//            for (int j = entryCount - 1; j >= 0; 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;
//
//                    //左右算法不一样,左边是从下往上排的,即你可以理解为饼图是顺时针方向,从零点排到12点的360度圆形,建议先看else里的,即右边的,方便理解
//                    if (transformedAngle % 360.0 >= 90.0 && transformedAngle % 360.0 <= 270.0) {//左边部分
//                        pt2x = center.x - radius - 5;
//                        if (lastPositionOfLeft == 0) {//第一个不用管
//                            pt2y = pt1y;
//                        } else {
//                            if (pt1y - lastPositionOfLeft < textHeight) {//如果上一个labley的位置减去计算出的pt1y的位置间距小于lable的高度,则需要在计算出的y基础上加上差的间距
//                                pt2y = pt1y + (textHeight - (pt1y - lastPositionOfLeft));//例如:lable高度5,计算出的pt1y位置10,上一个labley的位置12,则间距只有lastPositionOfRight-pt1y=2,还需要减去少的textHeight-(lastPositionOfRight-pt1y)=3才行
//                            } else {
//                                pt2y = pt1y;
//                            }
//                        }
//                        lastPositionOfLeft = pt2y;//记录上一个lableY方向的位置
//
//                        mValuePaint.setTextAlign(Paint.Align.RIGHT);
//
//                        if (drawXOutside)
//                            getPaintEntryLabels().setTextAlign(Paint.Align.RIGHT);
//
//                        labelPtx = pt2x - offset;
//                        labelPty = pt2y;
//
//                    } else {//右边部分
////                        pt2x = center.x + radius + 5;
////                        if (lastPositionOfRight == 0) {//第一个不用管
////                            pt2y = pt1y;
////                        } else {
////                            if (pt1y - lastPositionOfRight < textHeight) {//如果计算出的pt1y的位置减去上一个labley的位置间距小于lable的高度,则需要在计算出的y基础上加上差的间距
////                                pt2y = pt1y + (textHeight - (pt1y - lastPositionOfRight));//例如:lable高度5,计算出的pt1y位置10,上一个labley的位置8,则间距只有pt1y-lastPositionOfRight=2,还需要加上少的textHeight-(pt1y-lastPositionOfRight)=3才行
////                            } else {
////                                pt2y = pt1y;
////                            }
////                        }
////                        lastPositionOfRight = pt2y;//记录上一个lableY方向的位置
////                        mValuePaint.setTextAlign(Paint.Align.LEFT);
////
////                        if (drawXOutside)
////                            getPaintEntryLabels().setTextAlign(Paint.Align.LEFT);
////
////                        labelPtx = pt2x + offset;
////                        labelPty = pt2y;
//                        continue;
//                    }
//
//                    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) {
//
//                        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) {
//                            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(Paint.Align.CENTER);
//
//                    // draw everything, depending on settings
//                    if (drawXInside && drawYInside) {
//
//                        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));
//                    }
//                }
//
//                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();
//    }
}
  • 再创建一个PieChart的子类,重新父类init()方法,由于我是在ViewPager中使用的,顺便处理了下滑动冲突,不需要的同学,可以把onTouchEvent(MotionEvent evt)删掉,代码如下:
public class MyPieChart extends PieChart {
    PointF downPoint = new PointF();

    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);
    }

    @Override
    protected void init() {
        super.init();
        //此处把mRenderer替换成我们自己的PieChartRenderer
        mRenderer = new MyPieChartRenderer(this, mAnimator, mViewPortHandler);
    }

    @SuppressLint("ClickableViewAccessibility")
    @Override
    public boolean onTouchEvent(MotionEvent evt) {
        switch (evt.getAction()) {
            case MotionEvent.ACTION_DOWN:
                downPoint.x = evt.getX();
                downPoint.y = evt.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                if (Math.abs(evt.getX() - downPoint.x) > 5 || Math.abs(evt.getY() - downPoint.y) > 5) {
                    getParent().requestDisallowInterceptTouchEvent(true);
                }
                break;
        }
        return super.onTouchEvent(evt);
    }
}
  • 至此,就可以使用了,把我们代码中的PieChart都替换成MyPieChart就好了,赶紧试试吧,看有没有达到去除重叠的效果。

文中的bug已经在MPAndroidChart饼图(PieChart)Value值重叠的解决方法(二)中完美解决了,可以去看看

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,923评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,154评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,775评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,960评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,976评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,972评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,893评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,709评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,159评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,400评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,552评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,265评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,876评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,528评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,701评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,552评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,451评论 2 352

推荐阅读更多精彩内容