专栏首页Jack的Android之旅android自定义钟表android自定义钟表

android自定义钟表android自定义钟表

android自定义钟表

首先看看效果图先

time.gif

然后看看自定义的属性

<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>

自定义各参数的初始化

 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();
}

接下来就是设定这个自定义View的大小,在没有大小自适应的时候,view的高度我这位整个手机屏幕高度的三分之一,宽度为整个屏幕的宽度

 if(widthModel==MeasureSpec.EXACTLY){ width=widthSize; 
  }else{ 
  width=screemWidth; 
} if(heightModel==MeasureSpec.EXACTLY){ 
  height=heightSize; 
}else{
  height=screemHeight/3; 
} 

在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的圆

代码如下:

//画大圆 canvas.drawCircle(halfWidth,halfHeight,radius,paint); //画中间大圆 canvas.drawCircle(halfWidth,halfHeight,outCircle,inCirclePaint); //画中间小圆 canvas.drawCircle(halfWidth,halfHeight,inCircle,outCirclePaint);

GIF1.gif

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

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

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

git2.PNG

即旋转画出X轴Y轴为(0,-radius+LongCalibration)和(0,-radius)这两点的直线。接着就是画文字了,首先Rect计算出显示的数字的大小,再把canvas的原点移动半径减去刻度的长度和数字一半大小,自定义的间隙之后的距离,此时原点的位置就是需要画出的数字的位置,canvas在旋转-6*i的距离才能使字体竖直,效果如下:

time2.PNG

绘制时间指针

//获取时间指针对应的角度 
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(); 
}

这里需要说的是

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

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

time3.PNG

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

最后源码链接 如果对你有帮助就请给我给星星或喜欢吧

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 模仿QQ运动item的界面

    是不是很像呢,那具体是实现是怎样的呢,即使概括的来说就是 1.计算各个变量的值(记得是会随整个View的大小变化而变化)。 2其次利用好canvas.tra...

    HelloJack
  • 高仿QQ运动的周报界面

    这次高仿的是QQ运动的周报界面的网图。这个控件刚开始的时候以为代码量不大,没想到一路下来界面代码在加上动画代码还是蛮多的。好了老规矩先上图:

    HelloJack
  • 高仿支付宝9.9.2版本生活模块界面来讲解CoordinatorLayout,AppBarLayout,CollapsingToolbarLayout

    是不是很像支付宝的效果呢,我们今天就要通过讲解android5.0新出的控件CoordinatorLayout,AppBarLayout,CollapsingT...

    HelloJack
  • [-Flutter 自组篇-] 蛛网图+绘制+动画实践

    张风捷特烈
  • 小程序Canvas实践指南

    导语 总结在小程序canvas开发实践中遇到的一些问题和解决方法。 ? 1. 什么是 Canvas? 在 MDN 是这样定义 canvas 的: canvas...

    腾讯VTeam技术团队
  • Canvas学习系列一:初识canvas

    版权声明:本文为原创文章发布于公众号:Modeng , 你可以随意转载但请务必注明出处!!!关注微信公众号:Modeng,回复 「前端书籍」上百本经...

    六小登登
  • Canvas学习系列二:Canvas的坐标系统

    版权声明:本文为原创文章发布于公众号:Modeng , 你可以随意转载但请务必注明出处!!! https://blog.csdn.net/qq_321352...

    六小登登
  • canvas-入门

    定义 canvas是HTML5新增的一个重要元素,先看下它的定义: <canvas> is an HTML element which can be used ...

    前端黑板报
  • 用Python中的tkinter模块作图(续)

    Zoctopus
  • HTML5之canvas画板介绍

    • canvas 其实对于HTML来说很简单,只是一个标签元素而已,自己并没有行为,

    十月梦想

扫码关注云+社区

领取腾讯云代金券