自定义View -- 钟表

通过自定义 View 来实现一个钟表;


【代码分析】

重写 onDraw

画外圆
/**
* 画外圆和中心实心圆
* @param canvas
*/
private void drawCircle(Canvas canvas) {
  Paint paint = new Paint();
  paint.setColor(mRingColor);
  paint.setStyle(Paint.Style.STROKE);
  paint.setAntiAlias(true);
  paint.setDither(true);
  paint.setStrokeWidth(getDigit(2));
  canvas.drawCircle(mWidth/2, mHeight/2, mDiameter/2, paint);
 
  // 画中心的实心圆
  paint.setStyle(Paint.Style.FILL);
  paint.setColor(mCenterPointColor);
  canvas.drawCircle(mWidth/2, mHeight/2, getDigit(4), paint);
}

画刻度
/**
* 画刻度
* @param canvas
*/
private void drawScale(Canvas canvas) {
  Paint paint = new Paint();
  paint.setStrokeWidth(getDigit(1));
  paint.setTextSize(getDigit(10));
  paint.setAntiAlias(true);
  for(int i=0; i<60; i++){
 
      if(i%5 == 0){
          paint.setStrokeWidth(getDigit(2));
          paint.setColor(mLongScaleColor);
          paint.setTextSize(getDigit(15));
          String timeText = "" + i/5;
          if(i==0){
              timeText = "12";
          }
          canvas.drawLine(mWidth/2, mHeight/2 - mDiameter/2, mWidth/2, mHeight/2 - mDiameter/2 + 40, paint);
          paint.setColor(mTextColor);
          canvas.drawText(timeText, mWidth/2-paint.measureText(timeText)/2, mHeight/2-mDiameter/2+80, paint);
      } else {
          paint.setStrokeWidth(getDigit(1));
          paint.setTextSize(getDigit(15));
          paint.setColor(mShortScaleColor);
          canvas.drawLine(mWidth/2, mHeight/2 - mDiameter/2, mWidth/2, mHeight/2 - mDiameter/2 + 20, paint);
      }
      // 旋转画布,每次旋转6度
      canvas.rotate(6,mWidth/2, mHeight/2);
  }
}

画指针
/**
* 画指针:时针,分针,秒针
* @param canvas
*/
private void drawIndicator(Canvas canvas) {
  // 保存图层
  canvas.save();
  canvas.translate(mWidth/2f, mHeight/2f);
 
  Paint paint = new Paint();
  paint.setAntiAlias(true);
  paint.setDither(true);
  paint.setStrokeWidth(getDigit(3));
  paint.setColor(mHourColor);
  canvas.drawLine(0, 0, getLeftBy(H), getTopBy(H), paint);
 
  paint.setStrokeWidth(getDigit(2));
  paint.setColor(mMinuteColor);
  canvas.drawLine(0, 0, getLeftBy(M), getTopBy(M), paint);
 
  paint.setStrokeWidth(getDigit(1));
  paint.setColor(mSecondColor);
  canvas.drawLine(0, 0, getLeftBy(S), getTopBy(S), paint);
 
  // 合并图层
  canvas.restore();
}
private float getLeftBy(int indicator){
  float r=0f;
  float digit = 0;
 
  switch(indicator){
  case H:
      r = mHourR;
      // 根据分钟进行补充,每5分钟进一小格
      digit = ((mHour%12/12f*60 + mMinute/60f*5)) % 60;
      break;
  case M:
      r = mMinuteR;
      digit = mMinute;
      break;
  case S:
      r = mSecondR;
      digit = mSecond+1;
      break;
  }
 
  float left = (float) Math.sin(digit/60f * Math.PI*2) * r;
  if(digit<=30){
      return Math.abs(left);
  } else {
      return -Math.abs(left);
  }
}
 
private float getTopBy(int indicator){
  float r=0f;
  float digit = 0;
 
  switch(indicator){
  case H:
      r = mHourR;
      // 根据分钟进行补充,每5分钟进一小格
      digit = ((mHour%12/12f*60 + mMinute/60f*5)) % 60;
      break;
  case M:
      r = mMinuteR;
      digit = mMinute;
      break;
  case S:
      r = mSecondR;
      digit = mSecond+1;
      break;
  }
 
  float left = (float) Math.cos(digit/60f * Math.PI*2) * r;
  if(15<=digit && digit<=45){
      return Math.abs(left);
  } else {
      return -Math.abs(left);
  }
}

重写 onMesure
@Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
     mWidth = measuredWidth(widthMeasureSpec);
     mHeight = measuredHeight(heightMeasureSpec);
     setMeasuredDimension(mWidth, mHeight);
 
     // 钟表的外圆直径(除去 padding )
     mDiameter = Math.min(mWidth - getPaddingLeft() - getPaddingRight(), mHeight - getPaddingTop() - getPaddingBottom());
     // 时针半径外环半径的1/3
     mHourR = mDiameter/2f/3;
     // 分针半径为外环半径的1/2
     mMinuteR = mDiameter/2f/2;
     // 秒针半径为外环半径的1/1.5
     mSecondR = mDiameter/2f/1.5f;
 }
 private int measuredWidth(int widthMeasureSpec) {
     int result = 0;
     int specMode = MeasureSpec.getMode(widthMeasureSpec);
     int specSize = MeasureSpec.getSize(widthMeasureSpec);
     if(specMode == MeasureSpec.EXACTLY){
         result = specSize;
     } else {
         result = 500;
         if(specMode == MeasureSpec.AT_MOST){
             result = Math.min(result, specSize);
         }
     }
     return result;
 }
 
 private int measuredHeight(int heightMeasureSpec) {
     int result = 0;
     int specMode = MeasureSpec.getMode(heightMeasureSpec);
     int specSize = MeasureSpec.getSize(heightMeasureSpec);
     if(specMode == MeasureSpec.EXACTLY){
         result = specSize;
     } else {
         result = 500;
         if(specMode == MeasureSpec.AT_MOST){
             result = Math.min(result, specSize);
         }
     }
     return result;
 }

用新线程启动钟表
/**
  * 启动钟表
  */
 private void startClock(){
     new Thread(new Runnable() {
 
         @Override
         public void run() {
             while (true) {
                 Calendar calendar = Calendar.getInstance();
                 calendar.setTime(new Date());
                 int hour = calendar.get(Calendar.HOUR)+1;
                 int minute = calendar.get(Calendar.MINUTE);
                 int second = calendar.get(Calendar.SECOND);
                 setHour(hour);
                 setMinute(minute);
                 setSecond(second);
                 try {
                     Thread.sleep(1000);
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 }
             }
         }
     }).start();
 }

【源码下载】

猜你喜欢

转载自iaiai.iteye.com/blog/2344669