android自定義鐘表
首先看看效果圖先
然后看看自定義的屬性
<resources>
<!--鐘表整體顏色-->
<attr name="color" format="color"/>
<!--數(shù)字大小-->
<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>
自定義各參數(shù)的初始化
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;
//保存狀態(tài)
canvas.save();
//畫大圓
canvas.drawCircle(halfWidth,halfHeight,radius,paint);
//畫中間大圓
canvas.drawCircle(halfWidth,halfHeight,outCircle,inCirclePaint);
//畫中間小圓
canvas.drawCircle(halfWidth,halfHeight,inCircle,outCirclePaint);
//畫60個刻度和時鐘數(shù)字
drawClockScale(canvas);
//繪制時間指針
refreshTime(canvas);
//返回狀態(tài)
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);
接著就是要畫60個刻度和時鐘數(shù)字這是整個自定義的難點和重點得问,不說廢話先貼代碼:
畫60個刻度和時鐘數(shù)字
//畫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度,所以我們每一次循環(huán)都要把canvas旋轉6度即canvas.rotate(6)贰军。理解這個之后我們每次循環(huán)通過canvas.drawline畫出刻度玻蝌,其中LongCalibration是長刻度的長,而ShortCalibration就是短刻度的長词疼,
canvas.drawLine(0,-radius+LongCalibration,0,-radius,paint);
即旋轉畫出X軸Y軸為(0,-radius+LongCalibration)和(0,-radius)這兩點的直線俯树。接著就是畫文字了,首先Rect計算出顯示的數(shù)字的大小贰盗,再把canvas的原點移動半徑減去刻度的長度和數(shù)字一半大小许饿,自定義的間隙之后的距離,此時原點的位置就是需要畫出的數(shù)字的位置舵盈,canvas在旋轉-6*i的距離才能使字體豎直陋率,效果如下:
繪制時間指針
//獲取時間指針對應的角度
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的中心),剩下就是畫指針了菩浙。效果圖如下:
不用這是靜態(tài)圖锨能,最后調用postInvalidateDelayed(1000);
保證每個一秒就調用onDraw()方法來重繪View來實現(xiàn)view的每個一秒的動態(tài)變化,這樣就完成效果圖的功能芍耘。
最后源碼鏈接
如果對你有幫助就請給我給星星或喜歡吧