android柱形图

246 阅读3分钟

我正在参加「创意开发 投稿大赛」详情请看:掘金创意开发大赛来了!

  • 思路

1、定义一个布局容器用来做画布;

2、定义一个 View类 用 Paint 将要绘制的图像都绘制出来;

3、在调用的类里定义一个方法插入需要的数据以此绘图。

  • 用法

第一个参数不用多说了;

    第二个参数是一个字符串数组,是x轴的坐标刻度名称,同时x轴也依据此数组长度划分刻度轴,所以如果觉得x轴太密集了,这

里可以间隔传入空字符串代替原值,这样坐标轴刻度会间隔绘制显示;

    第三个参数是一个字符串数组,是y轴的坐标刻度名称,同时y轴也依据此数组长度划分刻度轴。

    第四个参数是一个整型数组的集合,集合最大长度只能为2,否则会出错,博主这里没做容错处理,所以尤其要注意。这个集合

代表了要绘制的柱状图的数值,传入的集合包含一个整型数组代表绘制单柱状图,包含两个整型数组代表绘制双柱状图。还要强调

一下的是,这里的两个整型数组长度相同,且比x轴坐标刻度数组长度少1,因为坐标刻度从0开始计算。

    第五个参数是一个整型值的集合,集合长度只能为3,否则会出错,这里也没有做容错处理所以请注意。这个集合代表了柱状图

里面要用到的颜色的数值,具体定义在 res\values\colors.xml 文件中。这个集合里面的三个整型数值代表的颜色分别为第一个柱子颜

色,第二个柱子颜色,要绘制的数值颜色。在单柱状图中,如果不希望柱图颜色间隔绘制,可以传入两个相同的颜色数值作为集合

前两个元素。这里没有对控制数值的是否显示封装一个方法另做处理,可以简单的设置集合第三个参数为透明色,已达到不显示数

值的效果。

  • 代码
public class CustomBarChart extends View {
 
    // 坐标单位
    private String[] xLabel;
    private String[] yLabel;
    // 曲线数据
    private List<int[]> dataList;
    private List<Integer> colorList;
    // 默认边距
    private int margin = 20;
    // 距离左边偏移量
    private int marginX = 30;
    // 原点坐标
    private int xPoint;
    private int yPoint;
    // X,Y轴的单位长度
    private int xScale;
    private int yScale;
    // 画笔
    private Paint paintAxes;
    private Paint paintCoordinate;
    private Paint paintRectF;
    private Paint paintValue;
 
    public CustomBarChart(Context context, String[] xLabel, String[] yLabel,
                          List<int[]> dataList, List<Integer> colorList) {
        super(context);
        this.xLabel = xLabel;
        this.yLabel = yLabel;
        this.dataList = dataList;
        this.colorList = colorList;
    }
 
    public CustomBarChart(Context context) {
        super(context);
    }
 
    /**
     * 初始化数据值和画笔
     */
    public void init() {
        xPoint = margin + marginX;
        yPoint = this.getHeight() - margin;
        xScale = (this.getWidth() - 2 * margin - marginX) / (xLabel.length - 1);
        yScale = (this.getHeight() - 2 * margin) / (yLabel.length - 1);
 
        paintAxes = new Paint();
        paintAxes.setStyle(Paint.Style.STROKE);
        paintAxes.setAntiAlias(true);
        paintAxes.setDither(true);
        paintAxes.setColor(ContextCompat.getColor(getContext(), R.color.color11));
        paintAxes.setStrokeWidth(4);
 
        paintCoordinate = new Paint();
        paintCoordinate.setStyle(Paint.Style.STROKE);
        paintCoordinate.setDither(true);
        paintCoordinate.setAntiAlias(true);
        paintCoordinate.setColor(ContextCompat.getColor(getContext(), R.color.color11));
        paintCoordinate.setTextSize(15);
 
        paintRectF = new Paint();
        paintRectF.setStyle(Paint.Style.FILL);
        paintRectF.setDither(true);
        paintRectF.setAntiAlias(true);
        paintRectF.setStrokeWidth(1);
 
        paintValue = new Paint();
        paintValue.setStyle(Paint.Style.STROKE);
        paintValue.setAntiAlias(true);
        paintValue.setDither(true);
        paintValue.setTextAlign(Paint.Align.CENTER);
        paintValue.setTextSize(10);
    }
 
    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawColor(ContextCompat.getColor(getContext(), R.color.color1));
        init();
        drawAxesLine(canvas, paintAxes);
        drawCoordinate(canvas, paintCoordinate);
        if (dataList.size() == 1) {
            drawBar(canvas, paintRectF, dataList.get(0), colorList);
            drawValue(canvas, paintValue, dataList.get(0), colorList.get(2));
        } else if (dataList.size() == 2) {
            drawBars(canvas, paintRectF, dataList, colorList);
            drawValues(canvas, paintValue, dataList, colorList.get(2));
        }
    }
 
    /**
     * 绘制坐标轴
     */
    private void drawAxesLine(Canvas canvas, Paint paint) {
        // X
        canvas.drawLine(xPoint, yPoint, this.getWidth() - margin / 6, yPoint, paint);
        canvas.drawLine(this.getWidth() - margin / 6, yPoint, this.getWidth() - margin / 2, yPoint - margin / 3, paint);
        canvas.drawLine(this.getWidth() - margin / 6, yPoint, this.getWidth() - margin / 2, yPoint + margin / 3, paint);
 
        // Y
        canvas.drawLine(xPoint, yPoint, xPoint, margin / 6, paint);
        canvas.drawLine(xPoint, margin / 6, xPoint - margin / 3, margin / 2, paint);
        canvas.drawLine(xPoint, margin / 6, xPoint + margin / 3, margin / 2, paint);
    }
 
    /**
     * 绘制刻度
     */
    private void drawCoordinate(Canvas canvas, Paint paint) {
        // X轴坐标
        for (int i = 0; i <= (xLabel.length - 1); i++) {
            paint.setTextAlign(Paint.Align.CENTER);
            int startX = xPoint + i * xScale;
            canvas.drawText(xLabel[i], startX, this.getHeight() - margin / 6, paint);
        }
 
        // Y轴坐标
        for (int i = 0; i <= (yLabel.length - 1); i++) {
            paint.setTextAlign(Paint.Align.LEFT);
            int startY = yPoint - i * yScale;
            int offsetX;
            switch (yLabel[i].length()) {
                case 1:
                    offsetX = 28;
                    break;
 
                case 2:
                    offsetX = 20;
                    break;
 
                case 3:
                    offsetX = 12;
                    break;
 
                case 4:
                    offsetX = 5;
                    break;
 
                default:
                    offsetX = 0;
                    break;
            }
            int offsetY;
            if (i == 0) {
                offsetY = 0;
            } else {
                offsetY = margin / 5;
            }
            canvas.drawText(yLabel[i], margin / 4 + offsetX, startY + offsetY, paint);
        }
    }
 
    /**
     * 绘制单柱形
     */
    private void drawBar(Canvas canvas, Paint paint, int data[], List<Integer> colorList) {
        for (int i = 1; i <= (xLabel.length - 1); i++) {
            int startX = xPoint + i * xScale;
            RectF rect = new RectF(startX - 5, toY(data[i - 1]), startX + 5, this.getHeight() - margin - 2);
            if (i % 2 == 1) {
                paint.setColor(ContextCompat.getColor(getContext(), colorList.get(0)));
            } else {
                paint.setColor(ContextCompat.getColor(getContext(), colorList.get(1)));
            }
            canvas.drawRect(rect, paint);
        }
    }
 
    /**
     * 绘制双柱形
     */
    private void drawBars(Canvas canvas, Paint paint, List<int[]> dataList, List<Integer> colorList) {
        for (int i = 1; i <= (xLabel.length - 1); i++) {
            int startX = xPoint + i * xScale;
            paint.setColor(ContextCompat.getColor(getContext(), colorList.get(0)));
            RectF rect1 = new RectF(startX - 20, toY(dataList.get(0)[i - 1]), startX - 10,
                    this.getHeight() - margin - 2);
            canvas.drawRect(rect1, paint);
 
            paint.setColor(ContextCompat.getColor(getContext(), colorList.get(1)));
            RectF rect2 = new RectF(startX - 5, toY(dataList.get(1)[i - 1]), startX + 5,
                    this.getHeight() - margin - 2);
            canvas.drawRect(rect2, paint);
        }
    }
 
    /**
     * 绘制单数值
     */
    private void drawValue(Canvas canvas, Paint paint, int data[], int color) {
        paint.setColor(ContextCompat.getColor(getContext(), color));
        for (int i = 1; i <= (xLabel.length - 1); i++) {
            canvas.drawText(data[i - 1] + "w", xPoint + i * xScale, toY(data[i - 1]) - 5, paintValue);
        }
    }
 
    /**
     * 绘制双数值
     */
    private void drawValues(Canvas canvas, Paint paint, List<int[]> dataList, int color) {
        paint.setColor(ContextCompat.getColor(getContext(), color));
        for (int i = 1; i <= (xLabel.length - 1); i++) {
            int startX = xPoint + i * xScale;
            int offsetY1 = 5;
            int offsetY2 = 5;
            if (dataList.get(0)[i - 1] == dataList.get(1)[i - 1]) {
                offsetY2 += 10;
            }
            if (i > 1) {
                if ((dataList.get(1)[i - 2] == dataList.get(0)[i - 1])) {
                    offsetY1 += 10;
                }
            }
            canvas.drawText(dataList.get(0)[i - 1] + "w", startX - 18,
                    toY(dataList.get(0)[i - 1]) - offsetY1, paintValue);
            canvas.drawText(dataList.get(1)[i - 1] + "w", startX + 3,
                    toY(dataList.get(1)[i - 1]) - offsetY2, paintValue);
        }
    }
 
    /**
     * 数据按比例转坐标
     */
    private float toY(int num) {
        float y;
        try {
            float a = (float) num / 100.0f;
            y = yPoint - a * yScale;
        } catch (Exception e) {
            return 0;
        }
        return y;
    }
 
}