关于MPAndroidChart中的RadarChart自定义x轴标签颜色

由于最近在做实验室的项目,需要进行绘图表示相关的数据,因此用到了MPAndroidChart这个出名的开源框架,具体的使用先不在这里进行赘述,后面有时间再去更新相关的各个控件的使用的方法及步骤
具体情况是:项目要使用RadarChart进行显示数据,因此进行一顿代码操作后得到的图如下:
关于MPAndroidChart中的RadarChart自定义x轴标签颜色_第1张图片
相关代码如下:`

	   	mRadarChart = findViewById(R.id.raderChart);
        XAxis xAxis = mRadarChart.getXAxis();
        YAxis yAxis = mRadarChart.getYAxis();
        yAxis.setAxisMinimum(0);
        List radarEntries = new ArrayList<>();
        for (int i = 0; i < 4; i++) {
            radarEntries.add(new RadarEntry((i+1)*10));
        }
        RadarDataSet dataSet = new RadarDataSet(radarEntries,"");
        RadarData radarData = new RadarData(dataSet);
        mRadarChart.animateXY(1000,1000);
        mRadarChart.setData(radarData);
        mRadarChart.invalidate();

这里就不贴出布局文件(布局文件就是一个RadarChart)以及Activity类的相关方法了,可以看到,上面的代码仅仅就是设置给RadarChart设置了数据,以及设置了X轴标签的Formatter。
这个时候我就在想,由于使用前面的BarChart以及PieChart时,我们可以用柱形图的颜色以及图例的方法来表明该项,但是RadarChart的y轴显示为点的连线,如何用颜色表示勒,而且即使用不同的颜色表示每一段的线段,那我们又如何去表示哪一段的线段表示的是哪一项勒(毕竟一条线段连接的是两个值),因此,我就还是回到了想去用图例和颜色的方法去表示哪一项。于是,我首先去重写了X轴的标签的IAxisValueFormatter函数,来显示x轴的标签与我的选项一致,效果图如下:
关于MPAndroidChart中的RadarChart自定义x轴标签颜色_第2张图片
相关代码如下:

 public class MyAxisValueFormatter implements IAxisValueFormatter {
    String[] mStrings = new String[]{
            "选项一", "选项二", "选项三","选项四"
    };
    public MyAxisValueFormatter() {
       // mFormat = new DecimalFormat("###,###,###,##0.0");
    }

    @Override
    public String getFormattedValue(float value, AxisBase axis) {
        return mStrings[(int)value];
    }  
}

进行到这一步,我就在想,接下来就是要设置x轴不同标签的颜色,然后再添加图例并在图的下方显示出来,就可以像BarChart或PieChart那样进行标注显示了。因此,我想要设置X轴的标签,那我就去X轴那里进行设置好了,于是,我在Activity中获得XAxis的地方,加上xAxis.setTextColor()的代码,以为就可以实现了,但是我发现setTextColor需要传入的参数是int color,也就是它只能接收一个颜色的int值,所以肯定不行;于是我又想,在我重写的MyAxisValueFormatter类中,必须要重写一个方法就是getFormattedValue(float value, AxisBase axis)方法,它带有两个参数,一个是x轴此处的值,一个是轴属性的基本类AxisBase。XAxis和YAxis都是继承AxisBase的,但是,我在AxisBase的类里面并没有发现setColor的方法,但是AxisBase又是继承ComponentBase的,因此我继续到该类里面去查找setColor的方法,因此我屁颠屁颠的到我重写的getFormattedValue(float value, AxisBase axis)的方法里加了一行代码:axis.setTextColor(VORDIPLOM_COLORS[(int)value+2]);我想,这个方法会在每个读取每个XAxis的值,我在它读取的时候设置该axis的颜色值,不就能用颜色来标注选项了吗(想想就有点高兴。。。偷偷乐一下)所以该重写的方法如下:

@Override
    public String getFormattedValue(float value, AxisBase axis) {
        axis.setTextColor(VORDIPLOM_COLORS[(int)value+2]);//VORDIPLOM_COLORS是一个颜色数组
        return mStrings[(int)value];
    }

于是运行着试了下,得到如下图:
关于MPAndroidChart中的RadarChart自定义x轴标签颜色_第3张图片
。。。好像高兴早了,颜色还是都一样,而且是最后一次设置的那个值,心态有点崩。于是我就在网上去找相关的大佬教程,发现连RadarChart的教程都很少,更何况其自定义属性的教程,但是无意中,却找到了一篇关于BarChart如何根据Y值的大小来设置柱状图的颜色,是要重写BarDataSet的getColor方法和SetColor方法,于是,我也去RardarDataSet的类里面去找关于color的方法,结果发现,原来是不同的娘生的,此时心里就有一句话不知当讲不当讲。。。但是重写的思路让我感觉可以尝试一下,首先,我确定了XAxis的setTextColor的方法是设置x轴标签的属性的,并且在ComponentBase这个类里面,但是其设置的值就是给一个变量赋值,并没有相关的控件的颜色属性的方法赋值。因此我转而将目光转到getFormattedValue这个方法中,去看是什么调用了该类,结果一看,有很多类都调用了,例如:XAxisRendererRadarChart、XAxisRenderer等,但仔细进去看才发现XAxisRendererRadarChart是XAxisRenderer的子类,因此先看XAxisRendererRadarChart,注意到它有String label = mXAxis.getValueFormatter().getFormattedValue(i, mXAxis)这样的一行代码,这不就是得到X轴标签的值吗?因此,我看了它这个调用的方法里面的代码,如下:

@Override
    public void renderAxisLabels(Canvas c) {
        if (!mXAxis.isEnabled() || !mXAxis.isDrawLabelsEnabled())
            return;
        final float labelRotationAngleDegrees = mXAxis.getLabelRotationAngle();
        final MPPointF drawLabelAnchor = MPPointF.getInstance(0.5f, 0.25f);

        mAxisLabelPaint.setTypeface(mXAxis.getTypeface());
        mAxisLabelPaint.setTextSize(mXAxis.getTextSize());
        mAxisLabelPaint.setColor(mXAxis.getTextColor());

        float sliceangle = mChart.getSliceAngle();

        // calculate the factor that is needed for transforming the value to
        // pixels
        float factor = mChart.getFactor();

        MPPointF center = mChart.getCenterOffsets();
        MPPointF pOut = MPPointF.getInstance(0,0);
        for (int i = 0; i < mChart.getData().getMaxEntryCountSet().getEntryCount(); i++) {

            String label = mXAxis.getValueFormatter().getFormattedValue(i, mXAxis);

            float angle = (sliceangle * i + mChart.getRotationAngle()) % 360f;

            Utils.getPosition(center, mChart.getYRange() * factor
                    + mXAxis.mLabelRotatedWidth / 2f, angle, pOut);

            drawLabel(c, label, pOut.x, pOut.y - mXAxis.mLabelRotatedHeight / 2.f,
                    drawLabelAnchor, labelRotationAngleDegrees);
        }

        MPPointF.recycleInstance(center);
        MPPointF.recycleInstance(pOut);
        MPPointF.recycleInstance(drawLabelAnchor);
    }

由上可以看到, for (int i = 0; i < mChart.getData().getMaxEntryCountSet().getEntryCount(); i++),for语句的确是每次都调用getFormattedValue方法去取X轴标签的值,而且是根据你轴标签的个数去取。而且,我还注意到,这里有个drawLabel方法,因此,我赶紧点进去看一下。接着到了XAxisRenderer的drawLabel方法,刚才说了XAxisRenderer是XAxisRendererRadarChart的父类,该代码如下:

protected void drawLabel(Canvas c, String formattedLabel, float x, float y, MPPointF anchor, float angleDegrees) {
        Utils.drawXAxisValue(c, formattedLabel, x, y, mAxisLabelPaint, anchor, angleDegrees);
    }

然后有个Utils.drawXAxisValue的方法,点进去看到如下代码:

public static void drawXAxisValue(Canvas c, String text, float x, float y,
                                      Paint paint,
                                      MPPointF anchor, float angleDegrees) {

        float drawOffsetX = 0.f;
        float drawOffsetY = 0.f;

        final float lineHeight = paint.getFontMetrics(mFontMetricsBuffer);
        paint.getTextBounds(text, 0, text.length(), mDrawTextRectBuffer);

        // Android sometimes has pre-padding
        drawOffsetX -= mDrawTextRectBuffer.left;

        // Android does not snap the bounds to line boundaries,
        //  and draws from bottom to top.
        // And we want to normalize it.
        drawOffsetY += -mFontMetricsBuffer.ascent;

        // To have a consistent point of reference, we always draw left-aligned
        Paint.Align originalTextAlign = paint.getTextAlign();
        paint.setTextAlign(Paint.Align.LEFT);

        if (angleDegrees != 0.f) {

            // Move the text drawing rect in a way that it always rotates around its center
            drawOffsetX -= mDrawTextRectBuffer.width() * 0.5f;
            drawOffsetY -= lineHeight * 0.5f;

            float translateX = x;
            float translateY = y;

            // Move the "outer" rect relative to the anchor, assuming its centered
            if (anchor.x != 0.5f || anchor.y != 0.5f) {
                final FSize rotatedSize = getSizeOfRotatedRectangleByDegrees(
                        mDrawTextRectBuffer.width(),
                        lineHeight,
                        angleDegrees);

                translateX -= rotatedSize.width * (anchor.x - 0.5f);
                translateY -= rotatedSize.height * (anchor.y - 0.5f);
                FSize.recycleInstance(rotatedSize);
            }

            c.save();
            c.translate(translateX, translateY);
            c.rotate(angleDegrees);

            c.drawText(text, drawOffsetX, drawOffsetY, paint);

            c.restore();
        } else {
            if (anchor.x != 0.f || anchor.y != 0.f) {

                drawOffsetX -= mDrawTextRectBuffer.width() * anchor.x;
                drawOffsetY -= lineHeight * anchor.y;
            }

            drawOffsetX += x;
            drawOffsetY += y;

            c.drawText(text, drawOffsetX, drawOffsetY, paint);
        }

        paint.setTextAlign(originalTextAlign);
    }

上面代码可以看到,最后执行的是c.drawText(text, drawOffsetX, drawOffsetY, paint);方法来绘制X轴的标签,颜色属性就在paint参数里。
因此反过来看一下这个paint哪来的,而经过查找后可以看到,这个paint就是Utils.drawXAxisValue方法中多传入的mAxisLabelPaint变量,也就是AxisRenderer中的mAxisLabelPaint变量,而在XAxisRendererRadarChar以及 XAxisRenderer的类中,我都找到了mAxisLabelPaint.setColor(mXAxis.getTextColor());这样的一句代码,而且不再循环体里面,到此,也就解答我为什么我设置X轴标签颜色的时候,只会有一种颜色,因为它只设定一个值。因此接下来的思路就简单了,我只用把mAxisLabelPaint.setColor(mXAxis.getTextColor());放到我每次获取标签String label = mXAxis.getValueFormatter().getFormattedValue(i, mXAxis);的那个循环体里面,然后在我重写的getFormattedValue(float value, AxisBase axis)方法中设置axis的颜色的值就好了,还要注意的是,因为用的是开源框架是不能修改的,因此需要重写。于是,我重写了XAxisRendererRadarChart,如下:

public class MyXAxisRendererRadarChart extends XAxisRendererRadarChart {
@Override
        public void renderAxisLabels(Canvas c) {

            if (!mXAxis.isEnabled() || !mXAxis.isDrawLabelsEnabled())
                return;

            final float labelRotationAngleDegrees = mXAxis.getLabelRotationAngle();
            final MPPointF drawLabelAnchor = MPPointF.getInstance(0.5f, 0.25f);

            mAxisLabelPaint.setTypeface(mXAxis.getTypeface());
            mAxisLabelPaint.setTextSize(mXAxis.getTextSize());
            //mAxisLabelPaint.setColor(mXAxis.getTextColor());

            float sliceangle = mChart.getSliceAngle();

            // calculate the factor that is needed for transforming the value to
            // pixels
            float factor = mChart.getFactor();

            MPPointF center = mChart.getCenterOffsets();
            MPPointF pOut = MPPointF.getInstance(0,0);
            for (int i = 0; i < mChart.getData().getMaxEntryCountSet().getEntryCount(); i++) {

                **String label = mXAxis.getValueFormatter().getFormattedValue(i, mXAxis);
                
                mAxisLabelPaint.setColor(mXAxis.getTextColor());**
                
                float angle = (sliceangle * i + mChart.getRotationAngle()) % 360f;

                Utils.getPosition(center, mChart.getYRange() * factor
                        + mXAxis.mLabelRotatedWidth / 2f, angle, pOut);
                
                drawLabel(c, label, pOut.x, pOut.y - mXAxis.mLabelRotatedHeight / 2.f,
                        drawLabelAnchor, labelRotationAngleDegrees);
            }

            MPPointF.recycleInstance(center);
            MPPointF.recycleInstance(pOut);
            MPPointF.recycleInstance(drawLabelAnchor);
        }
    }

我只粘贴了和原XAxisRendererRadarChart 中不同的方法的代码,其他的都一样。注意我用**标注的两句代码,是改变的。而XAxisRendererRadarChart又在RadarChart中使用了,因此,只需再重写RadarChart为MyRadarChart(其实就是复制粘贴一遍,然后把导入的XAxisRendererRadarChart类改为导入MyXAxisRendererRadarChart 即可),最后一步,就是在布局文件中使用重写的MyRadarChart,并在重写的getFormattedValue(float value, AxisBase axis)方法中设置axis的颜色的值就好了。布局如下:





    
        
    

重写的getFormattedValue(float value, AxisBase axis)方法如下:

public class MyAxisValueFormatter implements IAxisValueFormatter {
    //private DecimalFormat mFormat;
    String[] mStrings = new String[]{
            "选项一", "选项二", "选项三","选项四"
    };
    public static final int[] VORDIPLOM_COLORS = {
            Color.rgb(192, 255, 140), Color.rgb(255, 247, 140), Color.rgb(255, 208, 140),
            Color.rgb(140, 234, 255), Color.rgb(255, 140, 157), Color.rgb(193, 37, 82),
            Color.rgb(255, 102, 0), Color.rgb(245, 199, 0), Color.rgb(106, 150, 31),
            Color.rgb(179, 100, 53),Color.rgb(64, 89, 128), Color.rgb(149, 165, 124),
            Color.rgb(217, 184, 162), Color.rgb(191, 134, 134), Color.rgb(179, 48, 80)
    };
    public MyAxisValueFormatter() {
       // mFormat = new DecimalFormat("###,###,###,##0.0");
    }
    @Override
    public String getFormattedValue(float value, AxisBase axis) {
        axis.setTextColor(VORDIPLOM_COLORS[(int)value+2]);
        return mStrings[(int)value];
    } 
}

运行结果图如下:
关于MPAndroidChart中的RadarChart自定义x轴标签颜色_第4张图片
可以看出,四个选项的颜色不一致,达到了预期的效果。从无从下手到改写到成功的时间不长,但是收获感确实满满的(容我去哭一会,可把自己牛逼坏了,哈哈。。。)
有什么问题欢迎大家前来讨论!!!
最后,附上我的Demo:https://github.com/liuqiwei0/MPAndroidChartDemo

你可能感兴趣的:(安卓学习)