国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

Android實現簡單時鐘View的方法

2019-10-22 18:29:43
字體:
來源:轉載
供稿:網友

通過Canvas的平移與旋轉簡化繪圖邏輯是一個非常有用的技巧,下面的時鐘view就是利用這個方法完成的,省去了使用三角函數計算坐標的麻煩。

Android,時鐘,View

package com.example.swt369.simpleclock;import android.content.Context;import android.graphics.Canvas;import android.graphics.Paint;import android.support.annotation.Nullable;import android.util.AttributeSet;import android.view.View;import android.view.ViewTreeObserver;import android.widget.Toast;import java.util.Calendar;/** * Created by swt369 on 2017/8/20. */public class ClockView extends View {  //時鐘各個部件的長度  private float mScaleLengthLong;  private float mScaleLengthShort;  private float mTickLengthHour;  private float mTickLengthMinute;  private float mTickLengthSecond;  //view的寬和高  private float mWidth;  private float mHeight;  //時鐘半徑  private float mRadius;  //繪制各部件時用的Paint  private Paint mPaintScaleLong;  private Paint mPaintScaleShort;  private Paint mPaintOutline;  private Paint mPaintNum;  private Paint mPaintTickHour;  private Paint mPaintTickMinute;  private Paint mPaintTickSecond;  private ViewTreeObserver.OnPreDrawListener onPreDrawListener;  public ClockView(final Context context, @Nullable AttributeSet attrs) {    super(context, attrs);    onPreDrawListener = new ViewTreeObserver.OnPreDrawListener() {      //獲取view寬高并計算各個部件的長度      @Override      public boolean onPreDraw() {        mWidth = getMeasuredWidth();        mHeight = getMeasuredHeight();        mRadius = Math.min(mWidth,mHeight) / 2 * 0.95f;        mScaleLengthLong = mRadius * 0.1f;        mScaleLengthShort = mRadius * 0.05f;        mTickLengthHour = mRadius * 0.3f;        mTickLengthMinute = mRadius * 0.45f;        mTickLengthSecond = mRadius * 0.6f;        return true;      }    };    getViewTreeObserver().addOnPreDrawListener(onPreDrawListener);    //點擊顯示具體時間    setOnClickListener(new OnClickListener() {      @Override      public void onClick(View v) {        Calendar calendar = Calendar.getInstance();        String time = String.format("當前時間:%02d:%02d:%02d",            calendar.get(Calendar.HOUR_OF_DAY),calendar.get(Calendar.MINUTE),calendar.get(Calendar.SECOND));        Toast.makeText(context,time, Toast.LENGTH_SHORT).show();      }    });    //初始化所有Paint對象    initializePaints();  }  @Override  protected void onDraw(Canvas canvas) {    if(mWidth == 0 || mHeight == 0){      return;    }    if(onPreDrawListener != null){      getViewTreeObserver().removeOnPreDrawListener(onPreDrawListener);      onPreDrawListener = null;    }    //繪制時鐘    drawClock(canvas);    //一秒后重繪    postInvalidateDelayed(1000);  }  private void drawClock(Canvas canvas) {    //保存原始狀態    canvas.save();    //將坐標系原點移到中心,并逆時針旋轉90度。完成后x軸朝上。    canvas.translate(mWidth / 2,mHeight / 2);    canvas.rotate(-90);    //畫外圍輪廓    canvas.drawCircle(0,0,mRadius, mPaintOutline);    //畫刻度    for(int i = 0 ; i < 12 ; i++){      String num = String.valueOf(i == 0 ? 12 : i);      if(i % 3 == 0){        canvas.drawLine(mRadius,0,mRadius - mScaleLengthLong,0, mPaintScaleLong);      }else {        canvas.drawLine(mRadius,0,mRadius - mScaleLengthShort,0, mPaintScaleShort);      }      canvas.drawText(num,mRadius - mScaleLengthLong - mPaintNum.measureText(num) * 2,0, mPaintNum);      //順時針旋轉30度      canvas.rotate(30);    }    Calendar calendar = Calendar.getInstance();    //畫時針    int hour = calendar.get(Calendar.HOUR);    canvas.save();    canvas.rotate(hour * 30);    canvas.drawLine(0,0,mTickLengthHour,0,mPaintTickHour);    canvas.restore();    //畫分針    int minute = calendar.get(Calendar.MINUTE);    canvas.save();    canvas.rotate(minute * 6);    canvas.drawLine(0,0,mTickLengthMinute,0,mPaintTickMinute);    canvas.restore();    //畫秒針    int second = calendar.get(Calendar.SECOND);    canvas.save();    canvas.rotate(second * 6);    canvas.drawLine(0,0,mTickLengthSecond,0,mPaintTickSecond);    canvas.restore();    //恢復原始狀態    canvas.restore();  }  private void initializePaints(){    mPaintScaleLong = new Paint();    mPaintScaleLong.setAntiAlias(true);    mPaintScaleLong.setStrokeWidth(5);    mPaintScaleShort = new Paint();    mPaintScaleShort.setAntiAlias(true);    mPaintScaleShort.setStrokeWidth(3);    mPaintOutline = new Paint();    mPaintOutline.setStyle(Paint.Style.STROKE);    mPaintOutline.setAntiAlias(true);    mPaintOutline.setStrokeWidth(5);    mPaintNum = new Paint();    mPaintNum.setTextSize(30);    mPaintTickHour = new Paint();    mPaintTickHour.setAntiAlias(true);    mPaintTickHour.setStrokeWidth(6);    mPaintTickMinute = new Paint();    mPaintTickMinute.setAntiAlias(true);    mPaintTickMinute.setStrokeWidth(4);    mPaintTickSecond = new Paint();    mPaintTickSecond.setAntiAlias(true);    mPaintTickSecond.setStrokeWidth(2);  }}

代碼注釋已經比較詳細了,下面把比較重要的部分再說明一下:

//保存原始狀態canvas.save();//省略中間部分...//恢復原始狀態canvas.restore();

在繪圖開始時調用canvas.save(),可以保存下未經任何平移、旋轉操作的原始畫布狀態。在所有繪圖工作完成后調用canvas.restore(),可以恢復到上一次保存的狀態(類似進出棧的感覺)。

//將坐標系原點移到中心,并逆時針旋轉90度。完成后x軸朝上。canvas.translate(mWidth / 2,mHeight / 2);canvas.rotate(-90);

畫布的平移與旋轉可能比較抽象,可以想象成坐標系的平移與旋轉。調用canvas.translate(dx,dy)相當于將坐標原點向x,y方向移動了dx,dy的距離,調用canvas.rotate(degree)相當于坐標系順時針旋轉了degree°。

//畫刻度for(int i = 0 ; i < 12 ; i++){  String num = String.valueOf(i == 0 ? 12 : i);  if(i % 3 == 0){    canvas.drawLine(mRadius,0,mRadius - mScaleLengthLong,0, mPaintScaleLong);  }else {    canvas.drawLine(mRadius,0,mRadius - mScaleLengthShort,0, mPaintScaleShort);  }  canvas.drawText(num,mRadius - mScaleLengthLong - mPaintNum.measureText(num) * 2,0, mPaintNum);  //順時針旋轉30度  canvas.rotate(30);}

根據i值決定是畫大刻度(90°的倍數)還是小刻度。每次畫完一條之后將坐標系順時針旋轉30°,這樣保證每次畫的刻度線的坐標不變。

//一秒后重繪postInvalidateDelayed(1000);

作用是在1000ms(1s)后再次執行View的draw流程,產生指針運動的效果。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VEVB武林網。


注:相關教程知識閱讀請移步到Android開發頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 佛冈县| 邹城市| 云和县| 屏东市| 汪清县| 十堰市| 合江县| 麻城市| 文昌市| 阳西县| 衡阳市| 衡阳县| 开封县| 顺平县| 岑巩县| 当涂县| 睢宁县| 岗巴县| 瑞昌市| 伊宁县| 封开县| 黄浦区| 永州市| 运城市| 双城市| 武平县| 濮阳市| 双桥区| 错那县| 仲巴县| 大关县| 开江县| 宣城市| 武义县| 玛纳斯县| 铜梁县| 乌恰县| 光泽县| 公安县| 衢州市| 大连市|