自定义表盘(未彻底完成)

看到大家都在自定义view玩。我也来玩一下,其实自定义View,画图不难,难的是数据的计算。如果你要做一个可扩展的View,里面的数据肯定是要灵活可变的。

这个时候,你就不可以把数据写死。下面是我自定义的View。

首先要搞清楚Canvas绘图的角度计算。0刻度不是在上方。Canvas里面的画弧度的起始度数(0)是以钟表的三点钟为0刻度的。

所以,第一步是要画3/4的圆弧的表盘。

/**
     * 绘制表盘
     *
     * @param canvas
     */
    private void drawPlate(Canvas canvas, RectF oval) {
        //开始画表盘,仪表盘不是一个完整的圆,是3/4的圆,所以起始度数是134度,结束点是44(404)度。
        for (int i = 134; i < 405; i += (270 / scales.length)) {
            canvas.drawArc(oval, i, 2, false, paint);
            //最后一个连结弧不要
            if (i + 270 / scales.length < 405) {
                canvas.drawArc(oval, i + 4, 270 / scales.length - 6, false, paint);
            }
        }
    }

其中指针是一个只有2°的弧。其中数组scales为仪表盘的刻度数值,可以自定义。

绘制了表盘之后,开始绘制表盘指针读数,比如汽车读数为50的时候,应该是怎么样的。

 /**
     * 绘制读数
     *
     * @param canvas
     */
    private void drawRegistration(Canvas canvas, RectF oval) {
        // 用来更改值,判断是否是动画
        int prog = isStartCartoom ? cartoomProgress : polluteNum;
        /*开始画读数颜色*/
        int index_pro = getProIndex(prog);//当前所处的段位,比如100,在默认数据中属于第二段。101属于第三段
        int start_degrees = 138;//开始画颜色的起始度数
        float rotation = 0f;//指针偏转角度
        Log.e("info", "prog=" + prog);
        Log.e("info", "index_pro=" + index_pro);
        for (int i = 0; i < index_pro; i++) {
            int d_value = i == 0 ? scales[0] : scales[i] - scales[i - 1];
            num_paint.setColor(colors[i % colors.length]);// 设置圆环的颜色
            int end1 = prog < scales[i] ? i == 0 ? prog : prog - scales[i - 1] : d_value;
            end1 = end1 * (270 / scales.length - 6) / d_value;// 算出来画的角度
            canvas.drawArc(oval, start_degrees, end1, false, num_paint);
            rotation = start_degrees + 90 + end1;
            start_degrees += 45;
        }
        if (contains(prog)) {
            rotation = 225 + (270 / scales.length) * (index_pro - 1);
            Log.e("info", "rotation=" + rotation);
        }
        //指针
        drawPointer(canvas, rotation);
    }

    /**
     * 绘制指针
     *
     * @param canvas
     * @param rotation
     */
    private void drawPointer(Canvas canvas, float rotation) {
        // 用来更改值,判断是否是动画
        int prog = isStartCartoom ? cartoomProgress : polluteNum;
        //圆心X的坐标
        int centre = getWidth() / 2;
        int radius = (int) (centre - roundWidth / 2); // 圆环的半径
        float scaleX = defaultWidth / width;
        float scaleY = defaultHeight / height;
        //表盘指针
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.chart_index);
        /* 控制旋转 */
        Matrix matrix = new Matrix();
        /**
         * 开始画指针
         */
        float sx = (float) ((getWidth() / bitmap.getWidth()) * 0.8);
        matrix.setScale(sx, sx);
        matrix.setRotate(rotation);
        bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
        canvas.drawBitmap(bitmap, (radius - bitmap.getWidth() / 2) + 10 * scaleX, radius - bitmap.getHeight() / 2 + 10 * scaleY,
                new Paint());
        bitmap.recycle();
        float text_size = text_paint.measureText(String.valueOf(prog));
        text_paint.setColor(colors[getProIndex(prog) % colors.length]);
        canvas.drawText(String.valueOf(prog), radius - text_size / 2, centre + bitmap.getHeight() / 2 + 30, text_paint);
 }

当前最不可少的当然需要一个动画了。没有动画怎么都感觉不好看。

通过Timer来实现的动画,你也可以通过轻量级的异步线程AsyncTask来实现

class CartoomEngine {
        public Handler mHandler;
        public boolean mBCartoom; // 是否正在作动画
        public Timer mTimer; // 用于作动画的TIMER
        public MyTimerTask mTimerTask; // 动画任务
        public int mTimerInterval; // 定时器触发间隔时间(ms)
        public float mCurFloatProcess; // 作动画时当前进度值


        @SuppressLint("HandlerLeak")
        public CartoomEngine() {
            mHandler = new Handler() {

                @Override
                public void handleMessage(Message msg) {
                    // TODO Auto-generated method stub
                    switch (msg.what) {
                        case TIMER_ID: {
                            if (mBCartoom == false) {
                                return;
                            }
                            mCurFloatProcess += 1;
                            setCartoomProgress((int) mCurFloatProcess);
                            if (mCurFloatProcess >= polluteNum) {
                                stopCartoom();
                            }
                        }
                        break;
                    }
                }

            };

            mBCartoom = false;
            mTimer = new Timer();
            mTimerInterval = 5;
            mCurFloatProcess = 0;

        }

        public synchronized void startCartoom(int time) {
            if (time <= 0 || mBCartoom == true) {
                return;
            }
            mBCartoom = true;
            isStartCartoom = true;
            setCartoomProgress(0);
            mCurFloatProcess = 0;
            mTimerTask = new MyTimerTask();
            mTimer.schedule(mTimerTask, 0, mTimerInterval);

        }

        public synchronized void stopCartoom() {

            if (mBCartoom == false) {
                return;
            }
            mBCartoom = false;
            setNum(polluteNum);
            isStartCartoom = false;
            if (mTimerTask != null) {
                mTimerTask.cancel();
                mTimerTask = null;
            }
        }

        private final static int TIMER_ID = 0x0010;

        class MyTimerTask extends TimerTask {

            @Override
            public void run() {
                Message msg = mHandler.obtainMessage(TIMER_ID);
                msg.sendToTarget();
            }

        }
    }
完整的代码链接在代码片里

https://code.youkuaiyun.com/snippets/2022443

指针图片在附件里


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值