android自定义钟表

android自定义钟表

首先看看效果图先

这里写图片描述

<resources>
    <!--钟表整体颜色-->
    <attr name="color" format="color"/>
    <!--数字大小-->
    <attr name="numSize" format="dimension"/>
    <!--中心外圆半径-->
    <attr name="inCircle" format="integer"/>
    <!--中心内圆半径-->
    <attr name="outCircle" format="integer"/>
    <declare-styleable name="ClockView">
        <attr name="numSize"/>
        <attr name="color"/>
        <attr name="inCircle"/>
        <attr name="outCircle"/>
    </declare-styleable>
</resources>
 ```

```在xml界面的编写
<resources>
<com.example.jack.clock.widget.ClockView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:color="@color/colorPrimary"
        app:inCircle="15"
        app:outCircle="25"
        app:numSize="18dp"/>
</resources>
 ```





<div class="se-preview-section-delimiter"></div>

###自定义各参数的初始化
     public ClockView(Context context) {
        this(context,null);
    }

    public ClockView(Context context, AttributeSet attrs) {
        this(context, attrs,0);
    }

    public ClockView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        display=((WindowManager)getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
        screemWidth=display.getWidth();
        screemHeight=display.getHeight();

        float density=getResources().getDisplayMetrics().density;
        marginLongPoint=(int)density*8;
        maginShortPoint=(int)density*16;
        maginRadius=(int)density*10;
        maginText=(int)density*10;
        hourMargin=(int)density*75;
        minuteMargin=(int)density*40;

        TypedArray typedArray=context.getTheme().obtainStyledAttributes(attrs,R.styleable.ClockView,defStyleAttr,0);
        int numCount=typedArray.getIndexCount();
        for(int i=0;i<numCount;i++){
            int attr=typedArray.getIndex(i);
            switch(attr){
                case R.styleable.ClockView_numSize:
                    numSize=typedArray.getDimensionPixelSize(attr,(int) TypedValue
                          .applyDimension(TypedValue.COMPLEX_UNIT_SP,15,getResources().getDisplayMetrics()));
                    break;
                case R.styleable.ClockView_color:
                    color=typedArray.getColor(attr,Color.BLACK);
                    break;
                case R.styleable.ClockView_inCircle:
                    inCircle=typedArray.getInt(attr,15);
                    break;
                case R.styleable.ClockView_outCircle:
                    outCircle=typedArray.getInt(attr,25);
                    break;
            }
        }
        typedArray.recycle();
        initCanvas();
    }
    public void initCanvas(){
        paint=new Paint();
        paint.setColor(color);
        paint.setAntiAlias(true);
        paint.setStrokeWidth(3);
        paint.setStyle(Paint.Style.STROKE);
        paint.setShadowLayer(2,2,2,2);

        textPaint=new Paint();
        textPaint.setColor(color);
        textPaint.setTextAlign(Paint.Align.CENTER);
        textPaint.setAntiAlias(true);
        textPaint.setTextSize(numSize);
        textPaint.setDither(true);
        textPaint.setSubpixelText(true);

        inCirclePaint=new Paint();
        inCirclePaint.setColor(color);
        inCirclePaint.setAntiAlias(true);
        inCirclePaint.setStrokeWidth(15);
        inCirclePaint.setAlpha(100);
        inCirclePaint.setDither(true);

        outCirclePaint=new Paint();
        outCirclePaint.setColor(color);
        outCirclePaint.setAntiAlias(true);
        outCirclePaint.setStrokeWidth(15);
        outCirclePaint.setDither(true);

        secondPaint=new Paint();
        secondPaint.setColor(color);
        secondPaint.setAntiAlias(true);
        secondPaint.setStrokeWidth(5);
        secondPaint.setDither(true);
    }

<br/>





<div class="se-preview-section-delimiter"></div>

###接下来就是设定这个自定义View的大小,在没有大小自适应的时候,view的高度我这位整个手机屏幕高度的三分之一,宽度为整个屏幕的宽度 
      if(widthModel==MeasureSpec.EXACTLY){
            width=widthSize;
        }else{
            width=screemWidth;
        }
        if(heightModel==MeasureSpec.EXACTLY){
            height=heightSize;
        }else{
            height=screemHeight/3;
        }   






<div class="se-preview-section-delimiter"></div>

###在onDraw()方法里我们就可以开始画图了
    @Override
    protected void onDraw(Canvas canvas) {
        //得到圆的半径
        if(getWidth()>getHeight()){
            radius=getHeight()/2-maginRadius;
        }else{
            radius=getWidth()/2-maginRadius;
        }
        //获得View一半的宽度和高度
        halfWidth=getWidth()/2;
        halfHeight=getHeight()/2;
        //保存状态
        canvas.save();
        //画大圆
        canvas.drawCircle(halfWidth,halfHeight,radius,paint);
        //画中间大圆
        canvas.drawCircle(halfWidth,halfHeight,outCircle,inCirclePaint);
        //画中间小圆
        canvas.drawCircle(halfWidth,halfHeight,inCircle,outCirclePaint);
        //画60个刻度和时钟数字
        drawClockScale(canvas);
        //绘制时间指针
        refreshTime(canvas);
        //返回状态
        canvas.restore();
        //每隔一秒刷新
        postInvalidateDelayed(1000);
    }
首先我们画的是外部的圆圈和正中间的半透明的大圆和小圆 ,即得到整个view的中心点也就是一半的宽(halfWidth)和高(halfHeight)画半径为radius的圆




<div class="se-preview-section-delimiter"></div>

###代码如下:
        //画大圆
        canvas.drawCircle(halfWidth,halfHeight,radius,paint);
        //画中间大圆
        canvas.drawCircle(halfWidth,halfHeight,outCircle,inCirclePaint);
        //画中间小圆
        canvas.drawCircle(halfWidth,halfHeight,inCircle,outCirclePaint);       
效果:
    ![这里写图片描述](http://img.blog.csdn.net/20160911184742294)

接着就是要画60个刻度和时钟数字这是整个自定义的难点和重点,不说废话先贴代码:




<div class="se-preview-section-delimiter"></div>

###画60个刻度和时钟数字
     //画60个刻度
    public void drawClockScale(Canvas canvas){
        canvas.translate(halfWidth,halfHeight);
        canvas.save();
        //长指针的长
        LongCalibration=radius/marginLongPoint;
        //短指针的长
        ShortCalibration=radius/maginShortPoint;
        for(int i=0;i<pointNum;i++){
            if(i%5==0){
                //绘画文字
                canvas.save();
                Rect rect=new Rect();
                int number=i==0?12:(i/5);
                textPaint.getTextBounds((number+""),0,(number+"").length(),rect);
                canvas.translate(0,-radius+LongCalibration+((rect.bottom-rect.top)/2)+maginText);
                canvas.rotate(-6*i);
                canvas.drawText(number+"",0,(rect.bottom-rect.top)/2,textPaint);
                canvas.restore();
                //画线
                canvas.drawLine(0,-radius+LongCalibration,0,-radius,paint);
            }else{
                canvas.drawLine(0,-radius+ShortCalibration,0,-radius,paint);
            }
            canvas.rotate(6);
        }
        canvas.restore();
    }

pointNum=6060个指针刻度,我们先把canvas的坐标原点移动到整个View的中心即canvas.translate(halfWidth,halfHeight);接着这个圆是360度我们有60个刻度即每个刻度的旋转角度为6度,所以我们每一次循环都要把canvas旋转6度即canvas.rotate(6)。理解这个之后我们每次循环通过canvas.drawline画出刻度,其中LongCalibration是长刻度的长,而ShortCalibration就是短刻度的长,





<div class="se-preview-section-delimiter"></div>

canvas.drawLine(0,-radius+LongCalibration,0,-radius,paint);

这句代码的形象就是
    ![这里写图片描述](http://img.blog.csdn.net/20160911191353860)
即旋转画出X轴Y轴为(0,-radius+LongCalibration)和(0,-radius)这两点的直线。接着就是画文字了,首先Rect计算出显示的数字的大小,再把canvas的原点移动半径减去刻度的长度和数字一半大小,自定义的间隙之后的距离,此时原点的位置就是需要画出的数字的位置,canvas在旋转-6*i的距离才能使字体竖直,效果如下:
![这里写图片描述](http://img.blog.csdn.net/20160911211732853)





<div class="se-preview-section-delimiter"></div>

###绘制时间指针
    //获取时间指针对应的角度
    public void refreshTime(Canvas canvas){
    //获取获取当前的时间
        Calendar mCalendar=Calendar.getInstance();
        int tempHour=mCalendar.get(Calendar.HOUR);
        int tempMinute=mCalendar.get(Calendar.MINUTE);
        int tempSecond=mCalendar.get(Calendar.SECOND);
        int hourRotate=new Float(360*((float)tempHour/12)).intValue();
        //计算出份指针的旋转的角度
        int minuteRotate=new Float(360*((float)tempMinute/60)).intValue();
        //计算出时指针旋转的角度,注(时的角度是当前小时的角度再加分钟所引起小时偏转的角度)
        hourRotate+=new Float(30*((float)minuteRotate/360)).intValue();
        //计算出秒指针旋转的角度
        int secondRotate=new Float(360*((float)tempSecond/60)).intValue();
        drawCircleLine(canvas,hourRotate,minuteRotate,secondRotate);
    }

    //时间指针
    public void drawCircleLine(Canvas canvas,int hour,int minute,int second){
        marginLong=radius-LongCalibration-minuteMargin;
        marginShort=radius-LongCalibration-hourMargin;
        canvas.rotate(180);
        //画小时指针
        RectF hourRectF=new RectF(-pointRadio,-pointRadio,pointRadio,marginShort);
        canvas.save();
        canvas.rotate(hour);
        canvas.drawRoundRect(hourRectF,circular,circular,outCirclePaint);
        canvas.restore();
        //画分钟指针
        RectF minuteRectF=new RectF(-pointRadio,-pointRadio,pointRadio,marginLong);
        canvas.save();
        canvas.rotate(minute);
        canvas.drawRoundRect(minuteRectF,circular,circular,outCirclePaint);
        canvas.restore();
        //画秒指针
        canvas.save();
        canvas.rotate(second);
        canvas.drawLine(0,0,0,radius-10,secondPaint);
        canvas.restore();

    }
这里需要说的是 





<div class="se-preview-section-delimiter"></div>

RectF hourRectF=new RectF(-pointRadio,-pointRadio,pointRadio,marginShort);
“`
用来确定指针的位置,pointRadio代表的是这个矩形的半径,而 canvas.rotate(180);旋转180保证按我们正常的思路一样指针向上,设RectF的左上角为(-pointRadio,-pointRadio)是为了保持在中心点(注:此时canvas的原点是view的中心),剩下就是画指针了。效果图如下:
这里写图片描述

不用这是静态图,最后调用postInvalidateDelayed(1000);保证每个一秒就调用onDraw()方法来重绘View来实现view的每个一秒的动态变化,这样就完成效果图的功能。

最后源码链接:

RectF hourRectF=new RectF(-pointRadio,-pointRadio,pointRadio,marginShort);

用来确定指针的位置,pointRadio代表的是这个矩形的半径,而 canvas.rotate(180);旋转180保证按我们正常的思路一样指针向上,设RectF的左上角为(-pointRadio,-pointRadio)是为了保持在中心点(注:此时canvas的原点是view的中心),剩下就是画指针了。效果图如下:
这里写图片描述

不用这是静态图,最后调用postInvalidateDelayed(1000);保证每个一秒就调用onDraw()方法来重绘View来实现view的每个一秒的动态变化,这样就完成效果图的功能。

最后源码链接

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值