1. 程式人生 > >自定義View-自制簡單的鐘表

自定義View-自制簡單的鐘表

先上圖,效果大概就是這樣,秒針按秒走動,還有兩個齒輪不停的旋轉

這是一個自定義的View,齒輪是素材,其它的均為畫筆畫的。

大概的想法是:

1.繪製圓 

2.繪製刻度與數字(採用畫布的旋轉進行繪製比較簡單)

3.繪製錶針(同樣採用畫布的旋轉實現)

4.繪製齒輪,並實現齒輪的轉動

5.齒輪的轉動採用屬性動畫,不停的旋轉,錶針的動畫是在一個執行緒中,每個1秒,使用postInvalidate() 繪製一遍畫布

下面上程式碼:

package com.example.animation;

import java.util.Calendar;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.LinearInterpolator;

public class ClockView extends View{
	private Bitmap gbitmap;//那個綠色齒輪
	private Bitmap rbitmap;//那個紅色齒輪
	private Matrix gmatrix;//綠色齒輪的Matrix
	private Matrix rmatrix;//紅色齒輪的Matrix  齒輪的轉動是根據Matrix的setRoate來進行改變的
	private Paint paint;
	public ClockView(Context context, AttributeSet attrs) {
		super(context, attrs);
		init();
	}
	private void init() {
		paint = new Paint();
		paint.setAntiAlias(true);
		gbitmap = BitmapFactory.decodeResource(getResources(), R.drawable.g_gear);
		rbitmap = BitmapFactory.decodeResource(getResources(), R.drawable.r_gear);
		gmatrix = new Matrix();
		rmatrix = new Matrix();
		run();
		roate();
	}
	public void run(){
		new Thread(new Runnable() {
			
			@Override
			public void run() {
				while(true){
					postInvalidate();
					try {
						Thread.sleep(1000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		}).start();
	}
	//屬性動畫,是的齒輪旋轉
	public void roate(){
		final ValueAnimator vaAnimator = ValueAnimator.ofFloat(0,1.0f);
		vaAnimator.setDuration(3000);
		vaAnimator.setInterpolator(new LinearInterpolator());
		vaAnimator.setRepeatCount(ValueAnimator.INFINITE);
		vaAnimator.addUpdateListener(new AnimatorUpdateListener() {
			
			@Override
			public void onAnimationUpdate(ValueAnimator animation) {
				float degree = (Float) animation.getAnimatedValue()*360;
				gmatrix.setRotate(degree,gbitmap.getWidth()/2,gbitmap.getHeight()/2);//順時針轉動
				rmatrix.setRotate(-degree,rbitmap.getWidth()/2,rbitmap.getHeight()/2);//逆時針轉動
				postInvalidate();
			}
		});
		vaAnimator.start();
	}
	@Override
	protected void onDraw(Canvas canvas) {
		gmatrix.postTranslate(getWidth()/2+80,  getHeight()/2+160-gbitmap.getHeight()/2);//此處使用postTranslate,和setTranslate可以檢視一下
		canvas.drawBitmap(gbitmap,gmatrix, null);
		rmatrix.postTranslate( getWidth()/2+80-gbitmap.getWidth()-rbitmap.getWidth()/2, getHeight()/2+160-rbitmap.getHeight()/2);
		canvas.drawBitmap(rbitmap,rmatrix,null);
		 // 當前時間對應的角度
		Calendar calendar = Calendar.getInstance();
        float secRot = calendar.get(Calendar.SECOND) * 6;
        float minRot = calendar.get(Calendar.MINUTE) * 6 + 6 * secRot / 360F;
        float hrRot = (calendar.get(Calendar.HOUR_OF_DAY) % 12) * 30 + 30 * minRot / 360F;

		//繪製圓形錶盤
		paint.setStyle(Paint.Style.STROKE);
		paint.setStrokeWidth(5.0f);
		paint.setColor(Color.BLACK);
		canvas.drawCircle(getWidth()/2, getHeight()/2, getWidth()/2, paint);
		//繪製刻度
		for(int i= 0;i<12;i++){
			if(i==0||i==3||i==6||i==9){
				paint.setStrokeWidth(5.f);
				paint.setTextSize(40);
				canvas.drawLine(getWidth()/2, getHeight()/2-getWidth()/2, 
						getWidth()/2, getHeight()/2-getWidth()/2+60, paint);
				String number;
				if(i==0){
					number = String.valueOf(12);
				}else{
					number = String.valueOf(i);
				}
				canvas.drawText(number, getWidth()/2-paint.measureText(number)/2,
						getHeight()/2-getWidth()/2+90, paint);
			}else{
				paint.setStrokeWidth(3.0f);
				paint.setTextSize(30);
				canvas.drawLine(getWidth()/2, getHeight()/2-getWidth()/2, 
						getWidth()/2, getHeight()/2-getWidth()/2+60, paint);
				String number = String.valueOf(
						i);
				canvas.drawText(number, getWidth()/2-paint.measureText(number)/2,
						getHeight()/2-getWidth()/2+100, paint);
			}
			//通過使用旋轉畫布能更輕鬆的進行繪製
			canvas.rotate(30,getWidth()/2,getHeight()/2);
			
		}
		//繪製中心圓圈
		paint.setStyle(Paint.Style.FILL);
		canvas.drawCircle(getWidth()/2, getHeight()/2, 10, paint);
		//繪製錶針
		paint.setColor(Color.BLACK);
		canvas.translate(getWidth()/2, getHeight()/2);
		paint.setStrokeWidth(15);//時針
		canvas.rotate(hrRot-90, 0, 0);//旋轉繪製
		canvas.drawLine(0, 0, 100, 0, paint);
		canvas.rotate(-(hrRot-90), 0, 0);//需要將旋轉的角度返回,進行下一個正確的繪製
		paint.setStrokeWidth(10);//分針
		canvas.rotate(minRot-90, 0, 0);
		canvas.drawLine(0, 0, 200, 0, paint);
		canvas.rotate(-(minRot-90),0,0);
		paint.setStrokeWidth(5);
		paint.setColor(Color.RED);//秒針
		canvas.rotate(secRot-90,0,0);
		canvas.drawLine(0, 0, 230, 0, paint);
		canvas.rotate(-(secRot-90),0,0);
	}
	
}

至於那兩個齒輪,我是在easyicon上找的,進去搜索齒輪就有...

佈局檔案:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.animation.ClockActivity" >

    <com.example.animation.ClockView
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</RelativeLayout>

OK,有錯誤的地方請指出..