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

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

Demo下载(UpDating):https://github.com/JinBoy23520/MPAndroidChartDemoByJin

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


一丶慨述

虽然在MPAndroidChart项目实战(一)里面就说了双柱状图的实现,但毕竟那是旧的jar包版,而目前的项目开发,用到的都是新版本,所以还是说一下总结一下,不整理不知道,一整理吓一跳,问题还真不少。

二丶效果:

    

三丶实现功能

1.实现柱状图。

2.解决柱状图上换行拼接文字问题。

3.解决X轴文字偶尔不显示问题。

四丶看代码

1.项目复用率很高,先得有个BarChartEntry.Java

/**
 * 柱状图
 * Created by jin
 */

public class BarChartEntity extends BaseChartEntity<BarEntry> {
    public BarChartEntity(BarLineChartBase chart, List<BarEntry>[] entries, String[] labels, int[] chartColor, int valueColor, float textSize) {
        super(chart, entries, labels, chartColor, valueColor, textSize);
    }

    @Override
    protected void initChart() {
        super.initChart();
        mChart.getAxisLeft().setDrawGridLines(true);
        mChart.getAxisLeft().enableGridDashedLine(10f, 15f, 0f);
        mChart.getAxisLeft().setGridLineWidth(0.5f);
        mChart.getAxisLeft().setGridColor(Color.parseColor("#f5f5f5"));
        mChart.getAxisLeft().setDrawZeroLine(false);
        mChart.getAxisRight().setDrawZeroLine(false);
        mChart.getAxisRight().setZeroLineWidth(0f);
        mChart.getAxisLeft().setZeroLineWidth(0f);
        mChart.getAxisLeft().setDrawAxisLine(false);
        mChart.getXAxis().setDrawAxisLine(false);
        mChart.getXAxis().setAxisMinimum(0);

    }

    @Override
    protected void setChartData() {
        BarDataSet barDataSet;
        if (mChart.getData() != null && mChart.getData().getDataSetCount() > 0) {
            barDataSet = (BarDataSet) mChart.getData().getDataSetByIndex(0);
            barDataSet.setValues(mEntries[0]);
            mChart.getData().notifyDataChanged();
            mChart.notifyDataSetChanged();
        } else {
            barDataSet = new BarDataSet(mEntries[0], labels == null ? "" : labels[0]);
            barDataSet.setColors(mChartColors);
            List<Integer> colors = new ArrayList<>();
            for (int color : mChartColors) {
                colors.add(color);
            }
            barDataSet.setValueTextColors(colors);
            ArrayList<IBarDataSet> dataSets = new ArrayList<>();
            dataSets.add(barDataSet);
            BarData data = new BarData(dataSets);
            data.setValueTextSize(mTextSize);
            data.setBarWidth(0.9f);
            mChart.setData(data);
        }
    }


    public void setDrawValueAboveBar(boolean aboveBar) {
        ((BarChart)mChart).setDrawValueAboveBar(aboveBar);
    }

    /**
     * <p>设置bar宽度</p>
     * @param barWidth float
     */
    public void setBarWidth(float barWidth) {
        ((BarChart)mChart).getData().setBarWidth(barWidth);
    }
}

这样就可以直接添加方法用了

/**
 * 柱状图 该在X轴得文字显示在柱状图上
 */
private void updataBarChart() {
    mBarChart = (BarChart) mView.findViewById(R.id.new_the_bar_chart);
    List<BarEntry>[] entries = new ArrayList[3];
    final String[] labels = {
            getActivity().getResources().getString(R.string.actual_value),
            getActivity().getResources().getString(R.string.budget_value),
            getActivity().getResources().getString(R.string.yoy_value),};
    int[] cahrtColors = {
            Color.parseColor("#45A2FF"),
            Color.parseColor("#58D4C5"),
            Color.parseColor("#FDB25F")};

    final double[] values = new double[3];
    ArrayList<BarEntry> entries1 = new ArrayList<>();
    float actualValue = 10086;
    float budgetValue = 1001;
    float yoyValue = 12580;
    entries1.add(new BarEntry(0.5f, actualValue));
    entries1.add(new BarEntry(1.3f, budgetValue));
    entries1.add(new BarEntry(2.1f, yoyValue));

    values[0] = actualValue;
    values[1] = budgetValue;
    values[2] = yoyValue;
    entries[0] = entries1;

    if (mBarChart.getData() != null) {
        mBarChart.getData().clearValues();
    }
    BarChartEntity barChartEntity = new BarChartEntity(mBarChart, entries, labels, cahrtColors, Color.parseColor("#999999"), 13f);
    barChartEntity.setBarWidth(0.55f);
    barChartEntity.setDrawValueAboveBar(true);
    mBarChart.setPinchZoom(false);
    mBarChart.setScaleEnabled(false);

    mBarChart.animateY(2000, Easing.EasingOption.EaseInOutQuart);
    barChartEntity.setAxisFormatter(new IAxisValueFormatter() {
        @Override
        public String getFormattedValue(float value, AxisBase axis) {
            return "";
        }
    }, null);

    mBarChart.getLegend().setEnabled(false);

    /**
     * 拼接柱状图上文字,涉及到修改源码
     */
    mBarChart.getData().setValueFormatter(new IValueFormatter() {
        @Override
        public String getFormattedValue(float value, Entry entry, int dataSetIndex, ViewPortHandler viewPortHandler) {
            return labels[entry.getX() == 0.5f ? 0 : (entry.getX() == 1.3f ? 1 : 2)]
                    + "\n"
                    + mFormat.format(values[entry.getX() == 0.5f ? 0 : (entry.getX() == 1.3f ? 1 : 2)]);
        }
    });

    /**
     * 处理当数据都为0,不好看情况
     */
    float yMax = mBarChart.getData().getYMax() == 0 ? 100f : mBarChart.getData().getYMax();
    float delta = yMax / 5.5f;
    mBarChart.getAxisLeft().setAxisMaximum(yMax + delta);

    float yMin = mBarChart.getData().getYMin();
    if (yMin == 0) {
        yMin = 0;
    }
    float deltaMin = yMin / 5.0f;
    mBarChart.getAxisLeft().setAxisMinimum(yMin - deltaMin);
}

代码敲完,发现没报错,但问题了来,柱状图上的文字是在同一排显,方法getFormattedValue里的“\n”,换行符并没起到作用。

此刻埋怨(该死的设计师,把那行字写在X轴出不久OK,非要整在柱状图上),初级工程师满心抓狂,大神微微一下,可能是绘图的部分出问题,找到位置


方法 public void drawValue(Canvas c, IValueFormatter formatter, float value, Entry entry, int dataSetIndex, float x, float y, int color){}用到的是paint,是不支持换行符的,那么怎么办呢,换支持的textpaint。

/**
     * Draws the value of the given entry by using the provided IValueFormatter.
     *
     * @param c            canvas
     * @param formatter    formatter for custom value-formatting
     * @param value        the value to be drawn
     * @param entry        the entry the value belongs to
     * @param dataSetIndex the index of the DataSet the drawn Entry belongs to
     * @param x            position
     * @param y            position
     * @param color
     */
    public void drawValue(Canvas c, IValueFormatter formatter, float value, Entry entry, int dataSetIndex, float x, float y, int color) {
        mValuePaint.setColor(color);
        
        //回车换行符处理
        TextPaint textPaint = new TextPaint();
        textPaint.setColor(mValuePaint.getColor());
        textPaint.setTextSize(mValuePaint.getTextSize());
        textPaint.setAntiAlias(true);
        String valueTemp = formatter.getFormattedValue(value, entry, dataSetIndex, mViewPortHandler);

        StaticLayout myStaticLayout = new StaticLayout(valueTemp, 0, valueTemp.length(), textPaint,
                (int)textPaint.measureText(valueTemp), Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false);
        c.save();

        c.translate(x - myStaticLayout.getWidth() / 2, y - myStaticLayout.getHeight()); //开始画位置
        myStaticLayout.draw(c);
        c.restore();

//        c.drawText(formatter.getFormattedValue(value, entry, dataSetIndex, mViewPortHandler), x, y, mValuePaint);
    }
问题解决了。菜鸟此刻仰望大神,我要怎么才能像大神一样,大神微微一笑:“恶补Android 绘图部分,多读源码,Believe you can fly”

菜鸟恍然大悟,原来设计师并不是刁难自己,原来是磨练啊。


说完X轴文字放到柱状图上的,再说说,X轴显示时间段的。

看方法:

/**
 * X轴显示时间段的柱状图
 */
public void updataXBarChart(){
    final MonthItemEntity entity = new MonthItemEntity();
    xBarChart = (BarChart) mView.findViewById(R.id.new_x_bar_chart);
    List<BarEntry>[]entries = new ArrayList[1];
    //x轴坐标 控制显示位置,并不会在X轴上显示具体的值
    final float[] xlabels = new float[entity.getMonthDatas().size()];
    int[] color ={Color.parseColor("#7f45a2ff")};
    final String unit = "%";
    //x轴坐标增量
    float delta = 1;

    for (int index = 0, len = entity.getMonthDatas().size(); index < len; index ++) {
        xlabels[index] = index * delta + delta;
    }
    entries[0] = entity.getMonthEntries();
    BarChartEntity barChartEntity = new BarChartEntity(xBarChart, entries, null, color, Color.parseColor("#999999"), 10f);
    /*属性修改设置*/
    barChartEntity.setBarWidth(0.55f);
    barChartEntity.setDrawValueAboveBar(true);
    xBarChart.setPinchZoom(false);
    xBarChart.setScaleEnabled(false);
    xBarChart.getLegend().setEnabled(false);
    xBarChart.getXAxis().setTextSize(9f);
    xBarChart.getAxisLeft().setPosition(YAxis.YAxisLabelPosition.INSIDE_CHART);
    mBarChart.animateY(1000, Easing.EasingOption.EaseInOutQuart);
    /*X,Y坐标显示设置*/
    barChartEntity.setAxisFormatter(new IAxisValueFormatter() {
        @Override
        public String getFormattedValue(float value, AxisBase axis) {
            for (int index = 0,len = xlabels.length; index < len; index ++) {
                if (value == xlabels[index]) {
                    return entity.getMonthDatas().get(index).getBeginTime() + "-" + entity.getMonthDatas().get(index).getEndTime();
                }
            }
            return "";
        }
    }, new IAxisValueFormatter() {
        @Override
        public String getFormattedValue(float value, AxisBase axis) {
            return mFormat.format(value) + (unit.equals("%") ? unit : "");
        }
    });

    /*值显示设置*/
    xBarChart.getData().setValueFormatter(new IValueFormatter() {
        @Override
        public String getFormattedValue(float value, Entry entry, int dataSetIndex, ViewPortHandler viewPortHandler) {
            return mFormat.format(value) + (unit.equals("%") ? unit : "");
        }
    });
    
    /*Y轴最大值最小值设置,为了尽可能的显示完整数据*/
    float yMax = xBarChart.getData().getYMax() == 0 ? 100f :xBarChart.getData().getYMax();
    float yDelta = yMax / 5.5f;
    float axisMaximum = yMax + yDelta;
    if (axisMaximum < 5) {
        axisMaximum = 5;
    }
    xBarChart.getAxisLeft().setAxisMaximum(axisMaximum);
    float yMin = xBarChart.getData().getYMin();
    float deltaMin = yMin / 5.0f;
    xBarChart.getAxisLeft().setAxisMinimum(yMin - deltaMin);
}
理论上这样就OK了,设置了根据方法设置了XY的显示,然而X轴得文字去有一写无法显示,如效果图一。

这下有gg了,没时间还怎么用,找大神,这下大神也笑不出来了:“待我细细研究再做讨论”......

第二天,大神微微一笑,先看在显示X轴字符样式的方法里面的判断if (value == xlabels[index]),为什么我要这么去判断呢。我们知道X轴的值在显示上是平均分的,而我只有三个柱子的时候,我只要他显示三个值,所以用了xlabels[index]作为对比,只在整数位置显示拼接文字。那么问题又来了。X轴得Value是的浮点型,这样计算出柱子的平均位置就可能是浮点型,不等了自然就不显示。好了,改。

找到位置:


方法computeAxisValues(),把计算值改为int型

主要修改位置(截了修改位置的代码):

protected void computeAxisValues(float min, float max) {

    float yMin = min;
    float yMax = max;

    int labelCount = mAxis.getLabelCount();
    double range = Math.abs(yMax - yMin);

    if (labelCount == 0 || range <= 0 || Double.isInfinite(range)) {
        mAxis.mEntries = new float[]{};
        mAxis.mCenteredEntries = new float[]{};
        mAxis.mEntryCount = 0;
        return;
    }

    // Find out how much spacing (in y value space) between axis values
    int rawInterval = (int)range / labelCount;
    int interval = (int)Utils.roundToNextSignificant(rawInterval);

    if (interval == 0) {
        interval +=1;
    }

    // If granularity is enabled, then do not allow the interval to go below specified granularity.
    // This is used to avoid repeated values when rounding values for display.
    if (mAxis.isGranularityEnabled())
        interval = interval < mAxis.getGranularity() ? (int)mAxis.getGranularity() : interval;

    // Normalize interval
    double intervalMagnitude = Utils.roundToNextSignificant(Math.pow(10, (int) Math.log10(interval)));
    int intervalSigDigit = (int) (interval / intervalMagnitude);
    if (intervalSigDigit > 5) {
        // Use one order of magnitude higher, to avoid intervals like 0.9 or
        // 90
        interval = (int)Math.floor(10 * intervalMagnitude);
    }

    int n = mAxis.isCenterAxisLabelsEnabled() ? 1 : 0;

    // force label count
    if (mAxis.isForceLabelsEnabled()) {

        interval = (int) range / (int) (labelCount - 1);
        mAxis.mEntryCount = labelCount;

        if (mAxis.mEntries.length < labelCount) {
            // Ensure stops contains at least numStops elements.
            mAxis.mEntries = new float[labelCount];
        }

OK,运行代码,达到图二想要效果

五丶跪求关注下载源码,200粉小目标
欢迎关注我的博客及微信公众号,后面会给大家带来更多相关MPAndroidChart无法解决的仿MPAndroidChart图标自定义控件
源码下载记得顺便Star哦~
下载链接:https://github.com/JinBoy23520/MPAndroidChartDemoByJin

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页