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.像大神这样对开源代码做整理,封装好便于使用,这种封装优化思想需要学习
好了,就写到这里,如果给你带来帮助,记得关注一下博主哦!

写在最后微信扫码提问

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

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,887评论 25 707
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,067评论 4 62
  • Summer 2015 Report #024 - 04/23/15 Jianjian Wu 1. Plan fo...
    M遇见阅读 1,839评论 0 2
  • 不是长短 不是多少 身量相当 言谈相契 晨钟暮鼓 安之若素
    鱼zhk阅读 261评论 1 1
  • 作者似乎通篇探讨多的是爱、灵魂、自我寻找诸如此类的方式,比较形而上。 主要认为亲密关系要形成,从自己内心深处去挖掘...
    寒方芳阅读 458评论 0 0