【Android】自定义View -- 钟表

【问题】
  • 通过自定义 View 来实现一个钟表;
【效果图】
【Android】自定义View -- 钟表_第1张图片

【代码分析】

  1. 重写 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);
      }
      }
  2. 重写 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;
    }
  3. 用新线程启动钟表

     
        
    /**
    * 启动钟表
    */
    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();
    }
【源码下载】

你可能感兴趣的:(Android)