zoukankan      html  css  js  c++  java
  • Android直方图递增View

    继上次分析实现Android自定义View之扇形图之后,自己又画了下面的这个递增直方图,本来是想做个静态的直方图就完了,结果想想静态的没啥趣味,于是就加了递增

    运行图_

    1 从分析最终效果

    1. 界面上要展现的东西有:x和y两个坐标轴
    2. 主角直方图每列
    3. 直方图顶部文字

    2 再分析,要在屏幕上画这样的竖直列,怎样画?

    在屏幕上画图就是给指定的屏幕坐标点上色

    于是就想到只要能给出每列起始坐标高度的终点坐标,然后给起点和终点之间的点全部上色,最终就应该能有这样的效果

    接着去看我们的绘画师(canvas)有哪些工具能给我使用,找到有这两个工具,可能可以给我们使用

     drawPoint 画点
     drawLine 画直线
    

    再想想刚才想的:把起点和终点之间的点全部上色,不就是在起点和终点之间画一条直线嘛,想把线画成像直方图,可以直接把画笔调粗点不就可以了

    确定了,就用drawLine来试试

    3 接着把界面上的元素转换为数据

    看看每列直方图有哪些属性:

    1. 最明显:颜色 color
    2. 顶上的描述:name
    3. 底部的位置应该用x轴坐标来描述吧:x
    4. 每列的高度:y

    于是肯定就需要一个bean来存放每列直方图的数据

    public class HistogramData {
        public int value;       //数值
        public String name;     //文字描述
    
        public float persentage;    //占数据总数的百分比
        public float y;         //在直方图上的x轴坐标
        public float x;         //在直方图上的y轴坐标
        public int color;       //填充颜色
    
        public HistogramData(int value, String name) {
    	this.value = value;
    	this.name = name;
        }
    }
    

    4 结合Android的屏幕坐标,分析:

    1. Andriod屏幕的坐标系统默认是左上角为原点,正方向x轴向右,y轴向下
    2. View的画布(canvas)的坐标系统默认和屏幕的一样

    屏幕和画布坐标.png

    直方图的坐标系是以左下角为原点,所以首先就要获取直方图View画布在屏幕中的尺寸,然后找到左下角的点作为直方图的原点

    获取View在屏幕中的尺寸,只需在onSizeChanged中就可以得到

    protected void onSizeChanged(int w, int h, int oldw, int oldh){
        super.onSizeChanged(w, h, oldw, oldh);    
        this.w = w - 10;    
        this.h = h - 10;
    }
    

    这里减去10,是为了让直方图原点距离画布编辑有一定间隔

    由于画布坐标和直方图坐标的y轴方向是相反的,所以后面有关坐标的计算需要注意

    坐标注意.png

    如图:计算每列直方图的y轴坐标时,就需要通过( h - 列高度 )来得到,使用drawLine画线时还是这样

    canvas.drawLine(histogramData.x, h, histogramData.x, histogramData.y,paint);
    

    竖直方向是画从h到y的直线,而不是从0到y的直线

    5 具体实现

    通过上面的分析,基本上已经可以开始画直方图了

    会用到的变量

    private int[] mColors = {Color.BLUE, Color.DKGRAY, Color.CYAN, Color.RED, Color.GREEN};
    private ArrayList<HistogramData> datas;
    private Paint paint;            //画笔
    private int mWidth = 70;    //直方图宽
    private int width2 = 20;    //直方图间距
    private int w;              //画布宽
    private int h;              //画布高
    

    在onSizeChanged方法里确定了画布宽高之后,就会走到onDraw里开始画画

    画直方图坐标

    paint.setColor(Color.BLACK);
    paint.setStrokeWidth(5);
    canvas.drawLine(10, h, w, h, paint);      //画坐标系X轴
    canvas.drawLine(10, h, 10, 10, paint);    //画坐标系Y轴
    

    画每列直方图

    paint.setStrokeWidth(mWidth);
        paint.setStyle(Paint.Style.STROKE);
        if (null == datas) {
            return;
        }
        for (int i = 0; i < datas.size(); i++) {
            HistogramData histogramData = datas.get(i);
            paint.setColor(histogramData.color);
            canvas.drawLine(histogramData.x, h, histogramData.x, histogramData.y,paint);
    
            //直方图顶部文字
            paint.setColor(Color.BLACK);
            paint.setStyle(Paint.Style.FILL);
            canvas.drawText(histogramData.name, histogramData.x - mWidth / 4, histogramData.y - 10, paint);
        }
    

    6 实现递增

    递增的实现主要是在数据处理的时候加上了线程和handler

    public void setData(ArrayList<HistogramData> data) {
        this.datas = data;
        if (null == datas || datas.size() == 0) {
            return;
        }
        myHandler = new MyHandler(this);
        new Thread(new Runnable() {
            @Override
            public void run() {
                //计算数据总和
                float sum = 0;
                for (int i = 0; i < datas.size(); i++) {
                    sum += datas.get(i).value;
                }
                //计算数据占总数的百分比
                for (int i = 0; i < datas.size(); i++) {
                    HistogramData histogramData = datas.get(i);
                    histogramData.persentage = histogramData.value / sum;
                }
                //计算单列数据高度,并缓慢增加
                float startX, endY;
                for (int i = 0; i < datas.size(); i++) {
                    HistogramData histogramData = datas.get(i);
                    startX = (i + 1) * mWidth + i * width2;
                    endY = HistogramView.this.h - histogramData.persentage * HistogramView.this.h;
                    histogramData.color = mColors[i % mColors.length];
                    //注意:画布的坐标是左上角为原点,所以是
                    // 从 画布高-10 为起点, 数据高度 为终点
                    // 递减
                    for (int j = HistogramView.this.h; j >= endY; j--) {
                        histogramData.x = startX;
                        histogramData.y = j;
                        //通知UI更新
                        myHandler.sendEmptyMessage(0);
                        try {
                            Thread.sleep(10);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }).start();
    }
    

    最终效果就是上面那(cu)张(cao)GIF了_,自定义View还有很长的路要走

    完整代码请移步

  • 相关阅读:
    删库了一定要跑路吗?爱情 36 技之记忆重生!
    程序员和他的朋友们!
    聊起 BigTable,让你不再胆怯
    [Ant Design] Warning: Instance created by `useForm` is not connected to any Form element. Forget to pass `form` prop?
    Git 常用命令
    Git 名词解释
    js中void 0和undefined的区别
    js运算符优先级
    搭建React项目(低配版)
    mac常用shell指令笔记
  • 原文地址:https://www.cnblogs.com/jiy-for-you/p/6245623.html
Copyright © 2011-2022 走看看