Android倒計時電子鐘的實現(上篇),android上篇
習慣了Android的預設倒計時字型,這裡採用Canvas畫圖的方式實現倒計時時鐘效果,首先先看一下靜態效果
不難發現,每個數字都是一個小圓形,也可以改成一個小正方形等等,這些都是可以實現的。
這裡使用圓形。
仔細觀察數字發現其是由一個二維數組組成,類似如下所示:根據下面數組可以畫出0的,效果
{0,0,1,1,1,0,0}, {0,1,1,0,1,1,0}, {1,1,0,0,0,1,1}, {1,1,0,0,0,1,1}, {1,1,0,0,0,1,1}, {1,1,0,0,0,1,1}, {1,1,0,0,0,1,1}, {1,1,0,0,0,1,1}, {0,1,1,0,1,1,0}, {0,0,1,1,1,0,0}
具體如何?,可以先定義一個常量類,這裡也可以使用json格式,然後進行讀取。
/** * Constants.java * Copyright(C) 2014 * creator:cuiran 2014-12-19 下午2:28:34 */package com.cayden.countdown;/** * TODO * @author cuiran * @version 1.0.0 */public interface Constants {int[][] data0={ {0,0,1,1,1,0,0}, {0,1,1,0,1,1,0}, {1,1,0,0,0,1,1}, {1,1,0,0,0,1,1}, {1,1,0,0,0,1,1}, {1,1,0,0,0,1,1}, {1,1,0,0,0,1,1}, {1,1,0,0,0,1,1}, {0,1,1,0,1,1,0}, {0,0,1,1,1,0,0} };int[][] data1={ {0,0,0,1,1,0,0}, {0,1,1,1,1,0,0}, {0,0,0,1,1,0,0}, {0,0,0,1,1,0,0}, {0,0,0,1,1,0,0}, {0,0,0,1,1,0,0}, {0,0,0,1,1,0,0}, {0,0,0,1,1,0,0}, {0,0,0,1,1,0,0}, {1,1,1,1,1,1,1}};int[][] data2={ {0,1,1,1,1,1,0}, {1,1,0,0,0,1,1}, {0,0,0,0,0,1,1}, {0,0,0,0,1,1,0}, {0,0,0,1,1,0,0}, {0,0,1,1,0,0,0}, {0,1,1,0,0,0,0}, {1,1,0,0,0,0,0}, {1,1,0,0,0,1,1}, {1,1,1,1,1,1,1}};int[][] data3={ {1,1,1,1,1,1,1}, {0,0,0,0,0,1,1}, {0,0,0,0,1,1,0}, {0,0,0,1,1,0,0}, {0,0,1,1,1,0,0}, {0,0,0,0,1,1,0}, {0,0,0,0,0,1,1}, {0,0,0,0,0,1,1}, {1,1,0,0,0,1,1}, {0,1,1,1,1,1,0}};int[][] data4={ {0,0,0,0,1,1,0}, {0,0,0,1,1,1,0}, {0,0,1,1,1,1,0}, {0,1,1,0,1,1,0}, {1,1,0,0,1,1,0}, {1,1,1,1,1,1,1}, {0,0,0,0,1,1,0}, {0,0,0,0,1,1,0}, {0,0,0,0,1,1,0}, {0,0,0,1,1,1,1}};int[][] data5={{1,1,1,1,1,1,1}, {1,1,0,0,0,0,0}, {1,1,0,0,0,0,0}, {1,1,1,1,1,1,0}, {0,0,0,0,0,1,1}, {0,0,0,0,0,1,1}, {0,0,0,0,0,1,1}, {0,0,0,0,0,1,1}, {1,1,0,0,0,1,1}, {0,1,1,1,1,1,0}};int[][] data6={{0,0,0,0,1,1,0}, {0,0,1,1,0,0,0}, {0,1,1,0,0,0,0}, {1,1,0,0,0,0,0}, {1,1,0,1,1,1,0}, {1,1,0,0,0,1,1}, {1,1,0,0,0,1,1}, {1,1,0,0,0,1,1}, {1,1,0,0,0,1,1}, {0,1,1,1,1,1,0}};int[][] data7={{1,1,1,1,1,1,1}, {1,1,0,0,0,1,1}, {0,0,0,0,1,1,0}, {0,0,0,0,1,1,0}, {0,0,0,1,1,0,0}, {0,0,0,1,1,0,0}, {0,0,1,1,0,0,0}, {0,0,1,1,0,0,0}, {0,0,1,1,0,0,0}, {0,0,1,1,0,0,0}};int[][] data8={ {0,1,1,1,1,1,0}, {1,1,0,0,0,1,1}, {1,1,0,0,0,1,1}, {1,1,0,0,0,1,1}, {0,1,1,1,1,1,0}, {1,1,0,0,0,1,1}, {1,1,0,0,0,1,1}, {1,1,0,0,0,1,1}, {1,1,0,0,0,1,1}, {0,1,1,1,1,1,0}};int[][] data9={ {0,1,1,1,1,1,0}, {1,1,0,0,0,1,1}, {1,1,0,0,0,1,1}, {1,1,0,0,0,1,1}, {0,1,1,1,0,1,1}, {0,0,0,0,0,1,1}, {0,0,0,0,0,1,1}, {0,0,0,0,1,1,0}, {0,0,0,1,1,0,0}, {0,1,1,0,0,0,0}};int[][] data10={{0,0,0,0}, {0,0,0,0}, {0,1,1,0}, {0,1,1,0}, {0,0,0,0}, {0,0,0,0}, {0,1,1,0}, {0,1,1,0}, {0,0,0,0}, {0,0,0,0}};}
然後自訂一個CountDownView繼承SurfaceView,實現Runnable, Callback,Constants 這三個介面,之所以實現線程介面是為了後續動態改變時候使用。
具體代碼如下:
/** * CountDownView.java * Copyright(C) 2014 * creator:cuiran 2014-12-19 下午2:18:59 */package com.cayden.countdown.view;import java.util.ArrayList;import com.cayden.countdown.Constants;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.util.Log;import android.view.SurfaceHolder;import android.view.SurfaceHolder.Callback;import android.view.SurfaceView;/** * 倒計時View * @author cuiran * @version 1.0.0 */public class CountDownView extends SurfaceView implements Runnable, Callback,Constants {private static final String TAG="CountDownView";private SurfaceHolder mHolder; //用於控制SurfaceViewprivate Canvas mCanvas; //聲明畫布private Paint mPaint; //聲明畫筆 private Thread mThread; //聲明一個線程 private static final int RADIUS=10;//聲明小球半徑 private static final int MARGIN_TOP = 60; private static final int MARGIN_LEFT = 30; private ArrayList<int[][]> list=new ArrayList<int[][]>(); public CountDownView(Context context) {super(context); mHolder = this.getHolder(); //獲得SurfaceHolder對象 mHolder.addCallback(this); //添加狀態監聽 mPaint = new Paint(); //建立一個畫筆對象 mPaint.setColor(Color.BLUE); //設定畫筆的顏色 list.add(data0); list.add(data1); list.add(data2); list.add(data3); list.add(data4); list.add(data5); list.add(data6); list.add(data7); list.add(data8); list.add(data9); list.add(data10);}@Overridepublic void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {}@Overridepublic void surfaceCreated(SurfaceHolder arg0) { mThread = new Thread(this); //建立線程對象 mThread.start();}@Overridepublic void surfaceDestroyed(SurfaceHolder arg0) {}@Overridepublic void run() {try{mDraw();}catch(Exception e){Log.e(TAG,"run error",e);}}/** * 自訂繪圖方法 * 2014-12-19 下午2:22:45 * */public void mDraw() { mCanvas = mHolder.lockCanvas(); //獲得畫布對象,開始對畫布畫畫 mCanvas.drawColor(Color.BLACK); //設定畫布顏色為黑色 canvas(mCanvas); mHolder.unlockCanvasAndPost(mCanvas); //把畫布顯示在螢幕上}public void canvas(Canvas mCanvas) {//畫圓,(x軸,y軸,半徑,畫筆) int hours=12; int minutes=36; int seconds=24; canvasDigit( MARGIN_LEFT , MARGIN_TOP , hours/10 , mCanvas ); canvasDigit( MARGIN_LEFT + 15*(RADIUS+1) , MARGIN_TOP , hours%10 , mCanvas ); canvasDigit( MARGIN_LEFT + 30*(RADIUS + 1) , MARGIN_TOP , 10 , mCanvas ); canvasDigit( MARGIN_LEFT + 39*(RADIUS+1) , MARGIN_TOP , minutes/10 , mCanvas); canvasDigit( MARGIN_LEFT + 54*(RADIUS+1) , MARGIN_TOP , minutes%10 , mCanvas); canvasDigit( MARGIN_LEFT + 69*(RADIUS+1) , MARGIN_TOP , 10 , mCanvas); canvasDigit( MARGIN_LEFT + 78*(RADIUS+1) , MARGIN_TOP , seconds/10 , mCanvas); canvasDigit( MARGIN_LEFT + 93*(RADIUS+1) , MARGIN_TOP , seconds%10 , mCanvas);}public void canvasDigit(int x,int y,int num,Canvas mCanvas) {int [][] data=list.get(num);for(int i=0;i<data.length;i++){for(int j=0;j<data[i].length;j++){if(data[i][j]==1){mCanvas.drawCircle(x + j*2*(RADIUS+1)+(RADIUS+1), y + i*2*(RADIUS+1)+(RADIUS+1), RADIUS, mPaint); }}}}}
關鍵代碼是在畫圓時候中間間隔的一個計算公式
mCanvas.drawCircle(x + j*2*(RADIUS+1)+(RADIUS+1), y + i*2*(RADIUS+1)+(RADIUS+1), RADIUS, mPaint);
這裡引用了一個圖片:
圖片就是表示計算下一個圓的位置
然後在寫一個Activity 來顯示我們剛寫的View
package com.cayden.countdown;import android.app.Activity;import android.os.Bundle;import android.view.Menu;import android.view.Window;import android.view.WindowManager;import com.cayden.countdown.view.CountDownView;public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState); // 隱藏狀態列 this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); // 把Activity的標題去掉 requestWindowFeature(Window.FEATURE_NO_TITLE); // 設定布局 setContentView(new CountDownView(this));}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {// Inflate the menu; this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.main, menu);return true;}}最後運行效果就如最開始的圖片顯示的。