1. 程式人生 > 程式設計 >Android自定義鐘錶特效

Android自定義鐘錶特效

最近該忙的都忙完了,自己自定義一直是個弱項,也一直想整個鐘錶玩玩,網上看了一圈,學習了不少,下面自己做做自定義

首先,製作鐘錶第一步,肯定是畫個圓吧,這是最直接的思維了!

先建立自己的自定義類,繼承View ,重寫構造方法,在第一個和第二個構造中初始化畫筆,設定顏色等
第一個構造器類似於咱們直接New物件,第二個就是在xml檔案引用時用到的

public class Watch extends View {
 private Paint mPaint;
 private Context context;

 public Watch(Context context) {
  super(context);
  this.context = context;
  init();
 }

 public Watch(Context context,@Nullable AttributeSet attrs) {
  super(context,attrs);
  this.context = context;
  init();
 }


 public Watch(Context context,@Nullable AttributeSet attrs,int defStyleAttr) {
  super(context,attrs,defStyleAttr);
 }

 private void init() {
  mPaint = new Paint();
  //抗鋸齒
  mPaint.setAntiAlias(true);
  mPaint.setColor(Color.BLACK);
  //分三種,STROKE之繪製輪廓,不繪製內容;FILL,只繪製內容;FILL_AND_STROKE,內容和輪廓都繪製
  mPaint.setStyle(Paint.Style.STROKE);
 }

開始畫圓

//設定線寬,線寬預設是1 
mPaint.setStrokeWidth(2);
//在螢幕中心畫圓,半徑為螢幕的1/3
canvas.drawCircle(getWidth() / 2,getHeight() / 2,getWidth() / 3,mPaint);

畫圓心

//整個螢幕中心為圓心點
mPaint.setStrokeWidth(5);
canvas.drawPoint(getWidth() / 2,mPaint);

接下來開始畫表裡面的豎線

//安卓座標系預設實在左上角的,現在我們需要將座標軸移動到圓心位置,這樣利於我們繪製線
mPaint.setStrokeWidth(1);
//座標原點平移到圓心的位置
canvas.translate(getWidth() / 2,getHeight() / 2);
for (int i = 0; i < 360; i++) {
   //刻度線長度為20,一圈是360度,並且秒針轉一圈為60秒,所以一秒就對應360度/60秒=6度,那麼五秒也就是5*6 = 30度
   if (i % 30 == 0) { //長的
    canvas.drawLine(getWidth() / 3 - 25,mPaint);
   } else if (i % 6 == 0) { //中的
    canvas.drawLine(getWidth() / 3 - 14,mPaint);
   }
   //每繪製一次就旋轉1度,總共繪製了360條線
   canvas.rotate(1);
  }

效果

接著再繪製數字 save和restore是成對出現的,為了這一塊操作不影響下面的元素,一個儲存,一個取出的意思

canvas.save();
  for (int i = 0; i < 12; i++) {
   if (i == 0) {
    trans(canvas,12 + "",i * 30,mPaint);
   } else {
    trans(canvas,i + "",mPaint);
   }
  }
  canvas.restore();

//如果直接繪製數字的畫,文字也跟著旋轉了,數字有的就會倒著,所以執行下面這一系列操作,再去繪製數字就正常了
 public void trans(Canvas canvas,String text,int degree,Paint paint) {
  Rect rect = new Rect();
  paint.getTextBounds(text,text.length(),rect);
  //先將原來的座標軸旋轉30度
  canvas.rotate(degree);
  //將旋轉完成的座標軸平移到上方 它只是在y軸進行的平移,所以x軸為0,y軸也就是圓心的位置減去35,35是自己固定的位置,可適當自己修改;但是為負值,因為在y軸的上方,Android座標系往下為正數
  canvas.translate(0,-(getWidth() / 3 - 35));
  //這時在將原來旋轉的30都轉回去,此時的座標軸與開始的座標軸都是直立的,只不過現在的位置處於原來座標軸的 右上方
  canvas.rotate(-degree);
  //開始寫文字 1,2,3,。。。。。12 因為文字寫
  canvas.drawText(text,-rect.width() / 2,rect.height() / 2,paint);
  //寫完文字後開始將座標軸復原 先是順時針旋轉30都,
  canvas.rotate(degree);
  //再平移到圓心的位置
  canvas.translate(0,getWidth() / 3 - 35);
  //在逆時針平移30都
  canvas.rotate(-degree);
 }

最後繪製分針、秒針、時針

//秒針
  canvas.save(); //save方法作用是將畫布先儲存下來,為了不影響其他的元素,例如繪製兩張圖片,繪製完第一張接著繪製第二張,第二張可能就會受到第一張的影響,變形啊或者壓縮了
  mPaint.setColor(Color.RED);
  mPaint.setStyle(Paint.Style.STROKE);//繪製邊框
  mPaint.setStrokeWidth(2);//邊框寬度
  canvas.rotate(secondDegree);//這三個變數在下面程式碼中
  canvas.drawLine(0,-100,mPaint);//豎直的,只在Y軸上,所以X軸都為0,100其實是指標的長度,因為在上方,所以為負數
  canvas.restore();

  //分針
  canvas.save();
  mPaint.setColor(Color.BLACK);
  mPaint.setStyle(Paint.Style.STROKE);//繪製邊框
  mPaint.setStrokeWidth(4);//邊框寬度 比指標粗點
  canvas.rotate(minuteDegree);
  canvas.drawLine(0,-80,mPaint);
  canvas.restore();

  //時針
  canvas.save();
  //mPaint.setColor(Color.GREEN);
  mPaint.setStyle(Paint.Style.STROKE);//繪製邊框
  mPaint.setStrokeWidth(6);//邊框寬度 比指分針粗點
  canvas.rotate(hourDegree);
  canvas.drawLine(0,-60,mPaint);
  canvas.restore();

效果

最後讓三個針跑起來

private float secondDegree;
private float minuteDegree;
private float hourDegree;
private Timer timer = new Timer();
private TimerTask timerTask = new TimerTask() {
  @Override
  public void run() {
   if (secondDegree == 360) {
    secondDegree = 0;
   }
   if (minuteDegree == 360) {
    minuteDegree = 0;
   }
   if (hourDegree == 360) {
    hourDegree = 0;
   }

   //這三個變數的換算方式,變數名起分針和秒針起反了,也無所謂了
   //第一個360/60=6,也就是一秒鐘走六度
   //第二個6/60 分針一秒針走0.1度
   //時針,一秒鐘走1/120度
   secondDegree = secondDegree + 6;
   minuteDegree = minuteDegree + 0.1f;
   hourDegree = hourDegree + 1 / 120f;
   /**
    * 自定義View 重新整理介面有三種
    * 1:Invalidate() 如果只是內容變動,可使用此方法
    * 2:postInvalidate() 涉及到執行緒切換的
    * 3:requestLayout() view位置變動,需要呼叫此方法 涉及到RadioGroup
    */
   postInvalidate();//涉及到執行緒,介面重新整理需要使用此方法
  }
 };

 public void start() {
  timer.schedule(timerTask,1000);
 }

在下面的旋轉角度裡呼叫三個變數,重複的上面的程式碼 星星部分

 //秒針
  canvas.save(); 
  mPaint.setColor(Color.RED);
  mPaint.setStyle(Paint.Style.STROKE);
  mPaint.setStrokeWidth(2);
  **canvas.rotate(secondDegree);**
  canvas.drawLine(0,mPaint);
  canvas.restore();

  //分針
  canvas.save();
  mPaint.setColor(Color.BLACK);
  mPaint.setStyle(Paint.Style.STROKE);
  mPaint.setStrokeWidth(4);
  **canvas.rotate(minuteDegree);**
  canvas.drawLine(0,mPaint);
  canvas.restore();

  //時針
  canvas.save();
  //mPaint.setColor(Color.GREEN);
  mPaint.setStyle(Paint.Style.STROKE);
  mPaint.setStrokeWidth(6);
  **canvas.rotate(hourDegree);**
  canvas.drawLine(0,mPaint);
  canvas.restore();

最後在activity介面呼叫

<?xml version="1.0" encoding="utf-8"?>
<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"
 tools:context="com.liuguijie.customwatch.MainActivity">
 <com.liuguijie.customwatch.Watch
  android:id="@+id/watch"
  android:layout_centerInParent="true"
  android:layout_width="300dp"
  android:layout_height="300dp" />
</RelativeLayout>
//呼叫start方法
Watch watchView = findViewById(R.id.watch);
watchView.start();

基本就是這麼多,跑起來就可以了!

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。