• 自定义view(二)


      这里是自定义view(二),上一篇关于自定义view的一些基本知识,比如说自定义view的步骤、会涉及到哪些函数以及如何实现自定义属性,同时实现了一个很基础的自定义控件,一个自定义的计时器,需要看的人可以点击这个链接:http://www.cnblogs.com/YaoJianXun/p/5806926.html。

      这次讲的是如何通过坐标系的变化实现一些更复杂的自定义view绘制,上一次博客我们实现了一个类似于计时器的环形控件,这次我们在那个基础上再做一次改动,通过坐标系的变动实现下面的效果:

      这里想讲一下关于android坐标系的一些东西:

    1、android 坐标系

      在android中有两种常用坐标系:

    1.1 android坐标系

      android坐标系就是以屏幕左上方为原点,向右为x轴正方向,向下为y轴正方的坐标系,可以使用getLocationOnScreen(intlocation[])这个函数获取Android坐标系中点的位置,可就是视图左上角在android坐标系中的位置。

    1.2 视图坐标系

      这个坐标系描述的是子视图在父视图中的位置,就是子视图左上角在父视图总的位置,坐标系的原点在父视图的左上角,向右为x轴正方向,向下为y轴正方向。

    1.3 坐标系常用函数

    • view的方法:

      getTop():获取到的是view自身顶边到期父布局顶边的距离。

       getLeft():获取到的是view自身的左边到其父布局左边的距离。

       getBottom(),getRight()也同上,获取的分别是view自身下边右边到其父布局下边右边的距离。

    • MotionEvent的方法:

      getX():获取点击事件距离控件左边的距离,视图坐标。

       getY():获取点击事件距离控件上边的距离,视图坐标。

       getRawX(),getRawY(),同上,只是他们获取的android坐标系中的距离,绝对坐标。

    1.4 通过坐标系移动实现view绘制

      这里介绍两个函数:

    • translate():平移android坐标系
    • rotate():旋转android坐标系

      分析上面图中的效果如何实现:

    • 外围的圆形

      这个就不做讲述了,很容易实现的效果。

    • 表盘上的刻度

      这个就要分析一下了,首先画出12点的刻度很容,由于它是一条竖直的直线,只需要指定起止点就可以直接绘制出来了。那么其他的刻度呢,起止点就没有那么容易计算得到了,那么怎么办呢,这个时候其实只要将android坐标系以原点为中心旋转一定的角度,在绘制和12点方向一样的线,就可以了,只不过刻度不同,可能线的长度不同,这个需要设置条件语句进行具体判断,但是绘制的方向很容易就得出来了。下面是代码:

          for (int i = 0; i < 60; i++) {
                //通过旋转坐标系绘制刻度
                String degree = String.valueOf(i / 5);
                if (i % 15 == 0) {
                    mPaint2.setStrokeWidth(5);
                    mPaint2.setTextSize(30);
                    canvas.drawLine(mCircleXY, 20, mCircleXY, 80, mPaint2);
                    if (i == 0) {
                        canvas.drawText("12", mCircleXY - mPaint2.measureText(degree) / 2, 120, mPaint2);
                    } else {
                        canvas.drawText(degree, mCircleXY - mPaint2.measureText(degree) / 2, 120, mPaint2);
                    }
                } else if (i % 5 == 0) {
                    mPaint2.setStrokeWidth(5);
                    mPaint2.setTextSize(30);
                    canvas.drawLine(mCircleXY, 20, mCircleXY,60, mPaint2);
                    canvas.drawText(degree, mCircleXY - mPaint2.measureText(degree) / 2, 100, mPaint2);
                } else {
                    mPaint2.setStrokeWidth(5);
                    mPaint2.setTextSize(30);
                    canvas.drawLine(mCircleXY, 20, mCircleXY, 40, mPaint2);
                }
                canvas.rotate(6, mCircleXY, mCircleXY);
            }
    

      通过上面的代码也能看出,每次选择6度一共旋转60次,每次绘制线的时候判断一下,如果现在整点数,绘制的线长度长一点,如果是12点、3点、6点、9点绘制的线的长度要更长一点。

    • 绘制时针分针

      这个就更简单了,通过translate()函数移动android坐标系原点到表盘中间,在从中间画出两条长短不一的线就可以了。同时没过一秒,选择一定角度就可以了。下面是代码:

         //平移坐标系,绘制时针
            canvas.translate(mCircleXY, mCircleXY);
            canvas.drawLine(0, 0, 100, 100, mPaint3);
    
            //旋转坐标系,绘制分针
            canvas.rotate(6 * time, 0, 0);
            canvas.drawLine(0, 0, 100, 200, mPaint4);
    
            time++;
            postInvalidateDelayed(1000);

      下面是完整的全部代码:

    public class CustomView extends View {
        private float mCircleXY, mLength, mRadius;
        private Paint mPaint1 = new Paint();   //表圆弧
        private Paint mPaint2 = new Paint();   //表刻度
        private Paint mPaint3 = new Paint();   //表时针
        private Paint mPaint4 = new Paint();   //表秒针
        private WindowManager mWM;
        private int time = 0;
        private int hour = 0;
    
        public CustomView(Context context) {
            super(context);
            mPaint1.setStyle(Paint.Style.STROKE);
            mPaint1.setStrokeWidth(5);
            mPaint1.setAntiAlias(false);
            mPaint3.setStrokeWidth(20);
            mPaint4.setStrokeWidth(10);
            setValues();
        }
    
        public CustomView(Context context, AttributeSet attrs) {
            super(context, attrs);
            mPaint1.setStyle(Paint.Style.STROKE);
            mPaint1.setStrokeWidth(5);
            mPaint1.setAntiAlias(false);
            mPaint3.setStrokeWidth(20);
            mPaint4.setStrokeWidth(10);
            setValues();
        }
    
        private void setValues() {
            mWM = (WindowManager) getContext()
                    .getSystemService(Context.WINDOW_SERVICE);
            mLength = mWM.getDefaultDisplay().getWidth();
            mCircleXY = mLength / 2;
            mRadius = (float) (mLength * 0.5);
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            //绘制钟表外圈圆环
            canvas.drawCircle(mCircleXY, mCircleXY, mRadius-20, mPaint1);
            //消除锯齿
            canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG
                    | Paint.FILTER_BITMAP_FLAG));
            for (int i = 0; i < 60; i++) {
                //通过旋转坐标系绘制刻度
                String degree = String.valueOf(i / 5);
                if (i % 15 == 0) {
                    mPaint2.setStrokeWidth(5);
                    mPaint2.setTextSize(30);
                    canvas.drawLine(mCircleXY, 20, mCircleXY, 80, mPaint2);
                    if (i == 0) {
                        canvas.drawText("12", mCircleXY - mPaint2.measureText(degree) / 2, 120, mPaint2);
                    } else {
                        canvas.drawText(degree, mCircleXY - mPaint2.measureText(degree) / 2, 120, mPaint2);
                    }
                } else if (i % 5 == 0) {
                    mPaint2.setStrokeWidth(5);
                    mPaint2.setTextSize(30);
                    canvas.drawLine(mCircleXY, 20, mCircleXY,60, mPaint2);
                    canvas.drawText(degree, mCircleXY - mPaint2.measureText(degree) / 2, 100, mPaint2);
                } else {
                    mPaint2.setStrokeWidth(5);
                    mPaint2.setTextSize(30);
                    canvas.drawLine(mCircleXY, 20, mCircleXY, 40, mPaint2);
                }
                canvas.rotate(6, mCircleXY, mCircleXY);
            }
    
            //平移坐标系,绘制时针
            canvas.translate(mCircleXY, mCircleXY);
            canvas.drawLine(0, 0, 100, 100, mPaint3);
    
            //旋转坐标系,绘制分针
            canvas.rotate(6 * time, 0, 0);
            canvas.drawLine(0, 0, 100, 200, mPaint4);
    
            time++;
            postInvalidateDelayed(1000);
        }
    
    }
    

      这样就可以绘制出图中所示的表盘,源码的链接:https://github.com/jiushi555/CustomView/tree/master/CustomTimepiece。

      转载请标明出处。


    不是闷骚的程序员算不上程序员。我的微信公众号“那点鼻事”,在这里周一到周五每天一篇文章,与技术无关,只哈牛逼。

  • 相关阅读:
    C++雾中风景14:CRTP, 模板的黑魔法
    ClickHouse源码笔记1:聚合函数的实现
    C++雾中风景番外篇4:GCC升级二三事
    C++雾中风景13:volatile解惑
    AeroSpike踩坑手记1:Architecture of a Real Time Operational DBMS论文导读
    Linux 程序设计1:深入浅出 Linux 共享内存
    C++雾中风景番外篇3:GDB与Valgrind ,调试代码内存的工具
    C++雾中风景番外篇2:Gtest 与 Gmock,聊聊C++的单元测试
    C++雾中风景12:聊聊C++中的Mutex,以及拯救生产力的Boost
    用TensorFlow搭建一个万能的神经网络框架(持续更新)
  • 原文地址:https://www.cnblogs.com/YaoJianXun/p/5832939.html
Copyright © 2020-2023  润新知