自定义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。

  转载请标明出处。

 


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

posted @ 2016-09-02 11:49  建勋  阅读(282)  评论(0编辑  收藏  举报