編輯:關於Android編程
周末沒事在家想干點啥,記得一年多前面試,那公司直接發個面試題讓我做,其中就有讓我做一個簡單的表盤效果,不過當時沒做出來,所以也沒好意思去面試,今天就實現下,大概分如下幾步
第一步:畫一個簡單的圓
第二步:繪制刻度
第三步:繪制時,分,表指針
第四步:繪制當前時間文字
第五步:實現時間動態顯示
第一步畫一個圓是很簡單的,
package com.example.clockview; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.util.AttributeSet; import android.widget.ImageView; /** * Created by Adminis on 2016/11/6. */ public class ClockView extends ImageView { private static final String TAG = "ClockView"; private Paint mPaint; private int widhth = 200;//控件的寬度 private int height = 200;//控件的高度 private int padding = 5; 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); initPaint(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(widhth, height); } private void initPaint() { mPaint = new Paint(); mPaint.setStrokeWidth(3); mPaint.setStyle(Paint.Style.STROKE); mPaint.setColor(Color.parseColor("#666666")); mPaint.setAntiAlias(true); } @Override protected void onDraw(Canvas canvas) { drawCircle(canvas); } /** * 繪制圓 * @param canvas */ private void drawCircle(Canvas canvas) { mPaint.setStyle(Paint.Style.STROKE); canvas.drawCircle(widhth/2,height/2,widhth/2-padding,mPaint); } }
第二步:繪制刻度
/** * 繪制刻度 * @param canvas */ private void drawScale(Canvas canvas) { mPaint.setStyle(Paint.Style.FILL); canvas.drawLine(widhth / 2 - padding, padding, widhth / 2 - padding, padding + 4 + 8, mPaint); }效果圖:
但是我們要畫類似這種圖:
一起要畫12個這個線,那就相當於每二根線之間的角度就是360/12=30度
每換完一根線後畫布就旋轉30度
/** * 繪制刻度 * @param canvas */ private void drawScale(Canvas canvas) { mPaint.setStyle(Paint.Style.FILL); for(int i=0;i<12;i++){ if(i%3==0){// 12 3 6 9對應的線長點 canvas.drawLine(widhth / 2 - padding, padding, widhth / 2 - padding, padding + 4 + 15, mPaint); }else{ canvas.drawLine(widhth / 2 - padding, padding, widhth / 2 - padding, padding + 4 + 8, mPaint); } canvas.rotate(30, widhth / 2, widhth / 2); } }效果:
刻度就是利用了canvas的rotate()旋轉方法繪制上去的,但是得以圓的中心點為旋轉點
第三步繪制時 分 表 表針
這個繪制是根據當前的時間來指向的,
/** * 繪制時 分 表 指針 * @param canvas */ private void drawPointer(Canvas canvas) { mCalendar = Calendar.getInstance(); mHour = mCalendar.get(Calendar.HOUR); mMinuate = mCalendar.get(Calendar.MINUTE); mSecond = mCalendar.get(Calendar.SECOND); //小時的旋轉度 mDegrees = mHour*30+mMinuate/2; mPaint.setColor(Color.BLACK); canvas.save(); canvas.rotate(mDegrees, widhth / 2, widhth / 2); canvas.drawLine(widhth / 2, height / 2, widhth / 2, widhth / 2 - mHourLineLen, mPaint); canvas.restore(); //分鐘 mPaint.setColor(Color.RED); mDegrees = mMinuate*6+mSecond/10; canvas.save(); canvas.rotate(mDegrees, widhth / 2, widhth / 2); canvas.drawLine(widhth / 2, height / 2, widhth / 2, widhth / 2 - mHourLineLen, mPaint); canvas.restore(); //繪制表針 mPaint.setColor(Color.BLUE); mDegrees = mSecond*6; canvas.save(); canvas.rotate(mDegrees, widhth / 2, widhth / 2); canvas.drawLine(widhth / 2, height / 2, widhth / 2, widhth / 2 - mHourLineLen, mPaint); canvas.restore(); }
在這解釋下這個mDegrees這個值 比如現在是21:20 但是分為12小時制的話就是9:20 時就是9*30度=270度 但是這個時針指向9肯定是不對的,因為還有20分鐘呢?時針線肯定是在9和10之間指向,這麼這1小時之間是30度,就拿21:30這個時間來算,這個時候時針角度應該是30*9+30/2=285度 這就說明60分鐘1小時 而1小時是30度,也就是說每2分鐘時針角度應該動一下,根據這個原理分鐘和表之間的計算也是類似的,
還有一點要特別的注意2就是繪制完時針它是根據當前的時針數比如9然後旋轉30*9的 但是canvas使用了動畫完以後一定要恢復到原來的,不然你繪制分鐘就會出問題,我就遇到了這個問題,在這特別提醒下
特別改動下了:類全部代碼復制下看下效果:
package com.example.clockview; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.util.AttributeSet; import android.widget.ImageView; import java.util.Calendar; /** * Created by Adminis on 2016/11/6. */ public class ClockView extends ImageView { private static final String TAG = "ClockView"; private Paint mPaint; private int widhth = 200;//控件的寬度 private int height = 200;//控件的高度 private int padding = 5; private Calendar mCalendar; private int mHour;//小時 private int mMinuate;//分鐘 private int mSecond;//秒 private float mDegrees ;//因為圓是360度 我們有12個刻度 所以就是360/12 private int mHourLineLen;//時指針 線 private int mMinuateLine;//分鐘 線 private int mSecondLine ;//表鐘線 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); initPaint(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(widhth, height); mHourLineLen = (int) (widhth/2*0.6); mMinuateLine = (int) (widhth/2*0.7); mSecondLine = (int) (widhth/2*0.8); } private void initPaint() { mPaint = new Paint(); mPaint.setStrokeWidth(3); mPaint.setStyle(Paint.Style.STROKE); mPaint.setColor(Color.parseColor("#666666")); mPaint.setAntiAlias(true); } @Override protected void onDraw(Canvas canvas) { drawCircle(canvas); drawScale(canvas); canvasCenterCircle(canvas); drawPointer(canvas); } /** * 在 圓中心繪制一個點 * @param canvas */ private void canvasCenterCircle(Canvas canvas) { mPaint.setStyle(Paint.Style.FILL); canvas.drawCircle(widhth / 2, height / 2, 5, mPaint); } /** * 繪制圓 * @param canvas */ private void drawCircle(Canvas canvas) { mPaint.setStyle(Paint.Style.STROKE); canvas.drawCircle(widhth / 2, height / 2, widhth / 2 - padding, mPaint); } /** * 繪制刻度 * @param canvas */ private void drawScale(Canvas canvas) { mPaint.setStyle(Paint.Style.FILL); for(int i=0;i<12;i++){ if(i%3==0){// 12 3 6 9對應的線長點 canvas.drawLine(widhth / 2 - padding, padding, widhth / 2 - padding, padding + 4 + 15, mPaint); }else{ canvas.drawLine(widhth / 2 - padding, padding, widhth / 2 - padding, padding + 4 + 8, mPaint); } canvas.rotate(30, widhth / 2, widhth / 2); } } /** * 繪制時 分 表 指針 * @param canvas */ private void drawPointer(Canvas canvas) { mCalendar = Calendar.getInstance(); mHour = mCalendar.get(Calendar.HOUR); mMinuate = mCalendar.get(Calendar.MINUTE); mSecond = mCalendar.get(Calendar.SECOND); //小時的旋轉度 mDegrees = mHour*30+mMinuate/2; mPaint.setColor(Color.BLACK); canvas.save(); canvas.rotate(mDegrees, widhth / 2, widhth / 2); canvas.drawLine(widhth / 2, height / 2, widhth / 2, widhth / 2 - mHourLineLen, mPaint); canvas.restore(); //分鐘 mPaint.setColor(Color.parseColor("#666666")); mPaint.setStrokeWidth(5); mDegrees = mMinuate*6+mSecond/10; canvas.save(); canvas.rotate(mDegrees, widhth / 2, widhth / 2); canvas.drawLine(widhth / 2, height / 2, widhth / 2, widhth / 2 - mMinuateLine, mPaint); canvas.restore(); //繪制表針 mPaint.setStrokeWidth(2); mPaint.setColor(Color.parseColor("#666666")); mDegrees = mSecond*6; canvas.save(); canvas.rotate(mDegrees, widhth / 2, widhth / 2); canvas.drawLine(widhth / 2, height / 2, widhth / 2, widhth / 2 - mSecondLine, mPaint); canvas.restore(); } }
第四步就是繪制當前時間文字顯示在中心點下面:
/** * 繪制文字 * @param canvas */ private void drawStr(Canvas canvas) { mPaint.setTextSize(24); StringBuffer sb = new StringBuffer(); if(mHour<10){ sb.append("0").append(String.valueOf(mHour)).append(":"); }else{ sb.append(String.valueOf(mHour)).append(":"); } if(mMinuate<10){ sb.append("0").append(String.valueOf(mMinuate)).append(":"); }else{ sb.append(String.valueOf(mMinuate)).append(":"); } if(mSecond<10){ sb.append("0").append(String.valueOf(mSecond)); }else{ sb.append(String.valueOf(mSecond)); } String str = sb.toString(); int strW = (int) mPaint.measureText(str); canvas.drawText(str, widhth / 2 - strW / 2, widhth / 2 + 30,mPaint); }
最後一步就是利用Handler每秒去刷新界面就能做到動態的顯示時間了:
最後完整的代碼:
package com.example.clockview; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.os.Handler; import android.os.Message; import android.util.AttributeSet; import android.widget.ImageView; import java.util.Calendar; /** * Created by Adminis on 2016/11/6. */ public class ClockView extends ImageView { private static final String TAG = "ClockView"; private Paint mPaint; private int widhth = 200;//控件的寬度 private int height = 200;//控件的高度 private int padding = 5; private Calendar mCalendar; private int mHour;//小時 private int mMinuate;//分鐘 private int mSecond;//秒 private float mDegrees ;//因為圓是360度 我們有12個刻度 所以就是360/12 private int mHourLineLen;//時指針 線 private int mMinuateLine;//分鐘 線 private int mSecondLine ;//表鐘線 private Handler mHandler = new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); invalidate(); } }; 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); initPaint(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(widhth, height); mHourLineLen = (int) (widhth/2*0.6); mMinuateLine = (int) (widhth/2*0.7); mSecondLine = (int) (widhth/2*0.8); } private void initPaint() { mPaint = new Paint(); mPaint.setStrokeWidth(3); mPaint.setStyle(Paint.Style.STROKE); mPaint.setColor(Color.parseColor("#666666")); mPaint.setAntiAlias(true); } @Override protected void onDraw(Canvas canvas) { drawCircle(canvas); drawScale(canvas); canvasCenterCircle(canvas); drawPointer(canvas); drawStr(canvas); mHandler.sendEmptyMessage(1); } /** * 繪制文字 * @param canvas */ private void drawStr(Canvas canvas) { mPaint.setTextSize(24); StringBuffer sb = new StringBuffer(); if(mHour<10){ sb.append("0").append(String.valueOf(mHour)).append(":"); }else{ sb.append(String.valueOf(mHour)).append(":"); } if(mMinuate<10){ sb.append("0").append(String.valueOf(mMinuate)).append(":"); }else{ sb.append(String.valueOf(mMinuate)).append(":"); } if(mSecond<10){ sb.append("0").append(String.valueOf(mSecond)); }else{ sb.append(String.valueOf(mSecond)); } String str = sb.toString(); int strW = (int) mPaint.measureText(str); canvas.drawText(str, widhth / 2 - strW / 2, widhth / 2 + 30,mPaint); } /** * 在 圓中心繪制一個點 * @param canvas */ private void canvasCenterCircle(Canvas canvas) { mPaint.setStyle(Paint.Style.FILL); canvas.drawCircle(widhth / 2, height / 2, 5, mPaint); } /** * 繪制圓 * @param canvas */ private void drawCircle(Canvas canvas) { mPaint.setStyle(Paint.Style.STROKE); canvas.drawCircle(widhth / 2, height / 2, widhth / 2 - padding, mPaint); } /** * 繪制刻度 * @param canvas */ private void drawScale(Canvas canvas) { mPaint.setStyle(Paint.Style.FILL); for(int i=0;i<12;i++) { if (i % 3 == 0) {// 12 3 6 9對應的線長點 canvas.drawLine(widhth / 2 - padding, padding, widhth / 2 - padding, padding + 4 + 15, mPaint); }else{ canvas.drawLine(widhth / 2 - padding, padding, widhth / 2 - padding, padding + 4 + 8, mPaint); } canvas.rotate(30, widhth / 2, widhth / 2); } } /** * 繪制時 分 表 指針 * @param canvas */ private void drawPointer(Canvas canvas) { mCalendar = Calendar.getInstance(); mHour = mCalendar.get(Calendar.HOUR); mMinuate = mCalendar.get(Calendar.MINUTE); mSecond = mCalendar.get(Calendar.SECOND); //小時的旋轉度 mDegrees = mHour*30+mMinuate/2; mPaint.setColor(Color.BLACK); canvas.save(); canvas.rotate(mDegrees, widhth / 2, widhth / 2); canvas.drawLine(widhth / 2, height / 2, widhth / 2, widhth / 2 - mHourLineLen, mPaint); canvas.restore(); //分鐘 mPaint.setColor(Color.parseColor("#666666")); mPaint.setStrokeWidth(5); mDegrees = mMinuate*6+mSecond/10; canvas.save(); canvas.rotate(mDegrees, widhth / 2, widhth / 2); canvas.drawLine(widhth / 2, height / 2, widhth / 2, widhth / 2 - mMinuateLine, mPaint); canvas.restore(); //繪制表針 mPaint.setStrokeWidth(2); mPaint.setColor(Color.parseColor("#666666")); mDegrees = mSecond*6; canvas.save(); canvas.rotate(mDegrees, widhth / 2, widhth / 2); canvas.drawLine(widhth / 2, height / 2, widhth / 2, widhth / 2 - mSecondLine, mPaint); canvas.restore(); } }
終於寫完了!
剛群裡有人反映說3時和15秒時時針和表針線不重合的問題,於是我自己寫死了一個數據 測試了下發現真的是有這個bug 導致這個bug造成的原因是
/** * 繪制刻度 * @param canvas */ private void drawScale(Canvas canvas) { mPaint.setStyle(Paint.Style.FILL); for(int i=0;i<12;i++) { if (i % 3 == 0) {// 12 3 6 9對應的線長點 canvas.drawLine(widhth / 2-padding , padding, widhth / 2 -padding, padding + 4 + 15, mPaint); }else{ canvas.drawLine(widhth / 2-padding , padding, widhth / 2-padding, padding + 4 + 8, mPaint); } canvas.rotate(30, widhth / 2, widhth / 2); } }是這個x軸開始和結束點的坐標不對,應該把-padding去掉就正常了
改成後:
/** * 繪制刻度 * @param canvas */ private void drawScale(Canvas canvas) { mPaint.setStyle(Paint.Style.FILL); for(int i=0;i<12;i++) { if (i % 3 == 0) {// 12 3 6 9對應的線長點 canvas.drawLine(widhth / 2-padding , padding, widhth / 2 -padding, padding + 4 + 15, mPaint); }else{ canvas.drawLine(widhth / 2-padding , padding, widhth / 2-padding, padding + 4 + 8, mPaint); } canvas.rotate(30, widhth / 2, widhth / 2); } }
本文實例講述了Android編程實現換膚功能的方法。分享給大家供大家參考,具體如下:本系列專題培訓適用范圍:初級Android程序員,即有J2SE基礎和Android初級
本篇繼續來講自定義ViewGroup,給大家帶來一個實例:FlowLayout。何為FlowLayout,就是控件根據ViewGroup的寬,自動的往右添加,如果當前行剩
緒論:好久沒寫博客了,最近比較懶,不想寫博客,但是在看書,看一些Android進階的書,這裡小編也給大家推薦幾本適合進階的書,相信會對你有所幫助的。1.《Android群
魅族的魅藍手機通常都是只有移動和聯通版兩種版本的,但是最近最新發布的魅藍E再次吧魅藍手機推向了一個新的高度,很多機友就開始問小編了。魅族魅藍E支持什麼SIM