Android自定义View绘制条形统计图

最终效果

在这里插入图片描述

代码实现
package com.example.chartdemo;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathEffect;
import android.util.AttributeSet;
import android.view.View;

import androidx.annotation.Nullable;

import java.util.List;

public class BarChartView extends View {

    public BarChartView(Context context) {
        this(context,null);
    }

    public BarChartView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs,0);
    }

    public BarChartView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    private int widthMode;
    private int heightMode;
    private int widthSize;
    private int heightSize;
    private List<Integer> xItems;//X轴 轴项
    private String xUnit;//X轴 刻度单位
    private List<Integer> yItems;//Y轴 轴项
    private String yUnit;//Y轴 刻度单位
    private List<Integer> dataList;//数据
    private List<Integer> dataList2;//数据2
    private int xStepDistance;//X轴 步距
    private int yStepDistance;//Y轴 步距
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        widthMode = MeasureSpec.getMode(widthMeasureSpec);
        heightMode = MeasureSpec.getMode(heightMeasureSpec);
        widthSize = MeasureSpec.getSize(widthMeasureSpec);
        heightSize = MeasureSpec.getSize(heightMeasureSpec);

        initPaint();
    }

    private Paint linePaint;
    private Paint linePaint2;
    private Paint zhouPaint;
    private Paint gePaint;
    private Paint zhouTextPaint;
    private Paint line1DataTextPaint;
    private Paint line2DataTextPaint;
    private void initPaint(){
        linePaint=new Paint();
        linePaint.setStyle(Paint.Style.FILL_AND_STROKE);//不加这个不显示
        linePaint.setColor(Color.RED);
        linePaint.setStrokeWidth(4);
        linePaint.setAntiAlias(true);//抗锯齿功能
        linePaint.setARGB(100,255,0,0); //设置:A代表透明度  B代表红  G代表绿  B代表蓝 (范围:0————255)
        linePaint.setStrokeJoin(Paint.Join.ROUND);//线条连接处样式
        linePaint.setStrokeCap(Paint.Cap.ROUND);//设置线头模式
        /*Bitmap bm = BitmapFactory.decodeResource(getResources(), R.drawable._l9_line_back);
        BitmapShader bitmapShader = new BitmapShader(bm, Shader.TileMode.REPEAT, Shader.TileMode.MIRROR);
        linePaint.setShader(bitmapShader);*/

        linePaint2=new Paint();
        linePaint2.setStyle(Paint.Style.FILL_AND_STROKE);//不加这个不显示
        linePaint2.setColor(Color.BLUE);
        linePaint2.setStrokeWidth(4);
        linePaint2.setAntiAlias(true);//抗锯齿功能
        linePaint2.setARGB(100,0,0,255);
        linePaint2.setStrokeJoin(Paint.Join.ROUND);
        linePaint2.setStrokeCap(Paint.Cap.ROUND);

        gePaint=new Paint();
        gePaint.setColor(Color.parseColor("#A3AFB8"));
        gePaint.setStyle(Paint.Style.STROKE);//不加这个不显示
        gePaint.setStrokeWidth(0);
        gePaint.setAntiAlias(true);//抗锯齿功能
        PathEffect effects = new DashPathEffect(new float[]{5, 10}, 0);//设置绘制虚线
        gePaint.setPathEffect(effects);

        zhouPaint=new Paint();
        zhouPaint.setColor(Color.BLACK);
        zhouPaint.setStrokeWidth(4);
        zhouPaint.setAntiAlias(true);//抗锯齿功能

        zhouTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        zhouTextPaint.setTextSize(30);

        line1DataTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        line1DataTextPaint.setARGB(100,255,0,0);
        line1DataTextPaint.setTextSize(20);

        line2DataTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        line2DataTextPaint.setARGB(100,0,0,255);
        line2DataTextPaint.setTextSize(20);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        //画 X轴=====================================================================================
        canvas.drawLine(0,heightSize,widthSize, heightSize,zhouPaint);
        xStepDistance=widthSize/xItems.size();//X轴 步距值
        for (int a=0;a<xItems.size();a++){
            //画刻度
            canvas.drawLine(xStepDistance*a,heightSize,xStepDistance*a, heightSize-10,zhouPaint);
            //画格子
            Path gePath=new Path();
            gePath.moveTo(xStepDistance*a, heightSize);
            gePath.lineTo(xStepDistance*a, 0);
            gePath.close();
            canvas.drawPath(gePath, gePaint);
            //绘制X轴 刻度文字
            canvas.drawText(a==xItems.size()-1 ? xItems.get(a)+"("+xUnit+")" : xItems.get(a)+"", xStepDistance*a-10, heightSize-20, zhouTextPaint);
        }
        canvas.drawLine(widthSize,heightSize,widthSize-10,heightSize-10,zhouPaint);//画末尾箭头

        //画 Y轴=====================================================================================
        canvas.drawLine(0,0,0, heightSize,zhouPaint);
        yStepDistance=heightSize/yItems.size();//Y轴 步距值
        for (int a=0;a<yItems.size();a++){
            //画刻度
            if (a!=0)canvas.drawLine(0,heightSize-(yStepDistance*a),10, heightSize-(yStepDistance*a),zhouPaint);
            //画格子
            Path gePath=new Path();
            gePath.moveTo(0, heightSize-(yStepDistance*a));
            gePath.lineTo(widthSize, heightSize-(yStepDistance*a));
            gePath.close();
            canvas.drawPath(gePath, gePaint);
            //绘制Y轴 刻度文字
            canvas.drawText(a==yItems.size()-2 ? yItems.get(a)+"("+yUnit+")" : yItems.get(a)+"", 10, heightSize-(yStepDistance*(a+1)), zhouTextPaint);
        }
        canvas.drawLine(0,0,10,10,zhouPaint);//画末尾箭头

        //绘制_数据1===================================================================================
        double yDataPixel=heightSize/100f; //控件高度的像素个数——与——实际数据的对应关系值 (像素点分给100个数据值)
        for (int k=0;k<dataList.size();k++){
            //画方形条
            canvas.drawRect(xStepDistance*k+20,(int)(heightSize-(dataList.get(k)*yDataPixel)),xStepDistance*k+(xStepDistance/2)-30+20,heightSize,linePaint);
            canvas.drawText(dataList.get(k)+"", xStepDistance*k+20, (int)(heightSize-(dataList.get(k)*yDataPixel))-20, line1DataTextPaint);

        }

        //绘制_数据2===================================================================================
        for (int k=0;k<dataList2.size();k++){
            //画方形条
            canvas.drawRect(xStepDistance*k+(xStepDistance/2),(int)(heightSize-(dataList2.get(k)*yDataPixel)),xStepDistance*k+xStepDistance-30,heightSize,linePaint2);
            canvas.drawText(dataList2.get(k)+"", xStepDistance*k+(xStepDistance/2), (int)(heightSize-(dataList2.get(k)*yDataPixel))-20, line2DataTextPaint);
        }

    }

    /**
     * 设置曲线1 数据
     * @param dataList
     */
    public void setData(List<Integer> dataList){
        this.dataList=dataList;
        postInvalidate();
    }

    /**
     * 设置曲线2 数据
     * @param dataList
     */
    public void setData2(List<Integer> dataList){
        this.dataList2=dataList;
        postInvalidate();
    }

    /**
     * 设置X轴参数
     * @param xList
     * @param unit 刻度单位
     */
    public void setDataScaleX(List<Integer> xList,String unit){
        xItems=xList;
        xUnit=unit;
        postInvalidate();
    }

    /**
     * 设置Y轴参数
     * @param yList
     * @param unit 刻度单位
     */
    public void setDataScaleY(List<Integer> yList,String unit){
        yItems=yList;
        yUnit=unit;
        postInvalidate();
    }

}
使用方法
  1. 在XML中引用
<com.example.chartdemo.BarChartView
                android:id="@+id/bar_chart"
                android:background="#EFEFEF"
                android:layout_margin="20px"
                android:layout_width="match_parent"
                android:layout_height="600px" />
  1. 设置参数与数据
List<Integer> dataList=new ArrayList<>();
        dataList.add(85);
        dataList.add(90);
        dataList.add(70);
        dataList.add(68);
        dataList.add(50);
        dataList.add(43);
        dataList.add(28);
        dataList.add(21);
        dataList.add(30);
        dataList.add(58);
        dataList.add(70);
        dataList.add(55);

        List<Integer> dataList2=new ArrayList<>();
        dataList2.add(45);
        dataList2.add(67);
        dataList2.add(78);
        dataList2.add(98);
        dataList2.add(85);
        dataList2.add(54);
        dataList2.add(45);
        dataList2.add(35);
        dataList2.add(55);
        dataList2.add(59);
        dataList2.add(42);
        dataList2.add(45);

        List<Integer> xList=new ArrayList<>();
        xList.add(1);
        xList.add(2);
        xList.add(3);
        xList.add(4);
        xList.add(5);
        xList.add(6);
        xList.add(7);
        xList.add(8);
        xList.add(9);
        xList.add(10);
        xList.add(11);
        xList.add(12);

        List<Integer> yList=new ArrayList<>();
        yList.add(10);
        yList.add(20);
        yList.add(30);
        yList.add(40);
        yList.add(50);
        yList.add(60);
        yList.add(70);
        yList.add(80);
        yList.add(90);
        yList.add(100);

        BarChartView bar_chart=(BarChartView) findViewById(R.id.bar_chart);
        bar_chart.setDataScaleX(xList,"月");
        bar_chart.setDataScaleY(yList,"件");
        bar_chart.setData(dataList);
        bar_chart.setData2(dataList2);
		//===========动效数据================
		doBarChartDataList();

东西方法代码

private void doBarChartDataList(){
        for (int a=0;a<dataList.size();a++){
            new BarHeartbeat().start(50, a, dataList.get(a), new ActionCallback() {
                @Override
                public void toDo(Object o) {
                    List<Integer> list= (List<Integer>) o;
                    dataList.set(list.get(0),list.get(1));
                    bar_chart.setData(dataList);
                }
            });
        }

        for (int a=0;a<dataList2.size();a++){
            new BarHeartbeat().start(50, a, dataList2.get(a), new ActionCallback() {
                @Override
                public void toDo(Object o) {
                    List<Integer> list= (List<Integer>) o;
                    dataList2.set(list.get(0),list.get(1));
                    bar_chart.setData2(dataList2);
                }
            });
        }
    }

动效数据辅助类

package com.soface.chartdemo;

import android.os.Looper;
import android.os.Message;

import java.util.ArrayList;
import java.util.List;

/**
 * 心跳计时器
 */
public class BarHeartbeat {

    //事件标签
    public final int ACTION_TAG =0xFF;
    //要回调的接口
    private ActionCallback thisActionDo;

    //Handler事件监听器
    private android.os.Handler mHandler = new android.os.Handler(Looper.getMainLooper()){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what){
                case ACTION_TAG:
                    List<Integer> list= (List<Integer>) msg.obj;
                    thisActionDo.toDo(list);
                    break;
            }

        }
    };

    //启动
    public void start(int countDownTime,int index,int maxNumber,ActionCallback actionDo){

        thisActionDo=actionDo;

        for (int a=0;a<=maxNumber;a++){
            Message msg = mHandler.obtainMessage();
            msg.what = ACTION_TAG;

            List<Integer> list=new ArrayList<>();
            list.add(index);
            list.add(a);

            msg.obj=list;

            mHandler.sendMessageDelayed(msg,countDownTime*a);
        }
    };

}
package com.soface.chartdemo;

public interface ActionCallback {

    void toDo(Object o);

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

绝命三郎

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值