Android自定义view 时钟的绘制

2018-11-09  本文已影响19人  宝马奔驰_xyz

1. 绘制表盘

@Override

protected void onDraw(Canvas canvas) {

   super.onDraw(canvas);

  // 初次进入该方法时,进行坐标数据的计算

    if (!positionDataInitFlag) {

      scale =310f /mClockBitmap.getWidth();

      // 宽度中心取屏幕画布的一半处

      standardX = (int) (LeXingApplation.screenWidthPixels /2f); // 240

      // 高度取屏幕高度的0.43处

      standardY = (int) (LeXingApplation.screenHeightPixels *0.2f);

      clockWidth = (int) (LeXingApplation.screenWidthPixels *0.56f);

      Log.e("tag", "standardX=" +standardX +"standardY=" +standardY);

      clockHeight =clockWidth;

      clockLeftX = (int) (standardX -clockWidth /2f);// 92

      clockTopY = (int) (standardY -clockHeight /2f);// 196

      hitAreaXLeft = (int) (-clockWidth /2f); // -148

      hitAreaXRight = (int) (clockWidth /2f); // 148

      hitAreaYTop = (int) (clockHeight /2f); //

      hitAreaYBottom = (int) (-clockHeight /2f);

      clockCenterSizeHalf = (int) (30f *clockWidth / (2f *310f));

      // 指针的高度

      mHourNormalHeight = (int) (clockWidth *0.5f *0.75f);

      mHourPressHeight = (int) (clockWidth *0.5f *0.95f);

      mMinuteNormalHeight = (int) (clockWidth *0.5f *0.95f);

      mMinutePressHeight = (int) (clockWidth *0.5f *1.18f);

      //

      // 画表盘

      clockSrc.left =0;

      clockSrc.right =mClockBitmap.getWidth();

      clockSrc.top =0;

      clockSrc.bottom =mClockBitmap.getHeight();

      clockDst.left =clockLeftX;

      clockDst.top =clockTopY;

      clockDst.right =clockLeftX +clockWidth;

      clockDst.bottom =clockTopY +clockHeight;

      // 表心

      clockCenterSrc.left =0;

      clockCenterSrc.right = TimeSetActivity.clockCenterBitmap.getWidth();

      clockCenterSrc.top =0;

      clockCenterSrc.bottom = TimeSetActivity.clockCenterBitmap

            .getHeight();

      clockCenterDst.right =standardX +clockCenterSizeHalf;

      clockCenterDst.left =standardX -clockCenterSizeHalf;

      clockCenterDst.bottom =standardY +clockCenterSizeHalf;

      clockCenterDst.top =standardY -clockCenterSizeHalf;

       // 帮助按钮

      helpSrc.left =0;

      helpSrc.right = TimeSetActivity.helpNormalBitmap.getWidth();

      helpSrc.top =0;

      helpSrc.bottom = TimeSetActivity.helpNormalBitmap.getHeight();

      int helpButtonWidth = (int) (64f /30f *2f *clockCenterSizeHalf);

      helpDst.left =clockDst.right;

      helpDst.right =clockDst.right +helpButtonWidth;

      helpDst.top =clockDst.top;

      helpDst.bottom =clockDst.top +helpButtonWidth;

       // 设置初始化位置数据标志位, 重新绘图时无需再次初始化

      positionDataInitFlag =true;

  }

// 画表盘

  // 画出指定的位图,位图将自动-->缩放/自动转换,以填补目标矩形

  if (mClockBitmap !=null) {

canvas.drawBitmap(mClockBitmap, clockSrc, clockDst, null);

  }else {

     mClockBitmap = TimeSetActivity.clockNormalBitmap;

      canvas.drawBitmap(mClockBitmap, clockSrc, clockDst, null);

  }

// 画表心

  canvas.drawBitmap(TimeSetActivity.clockCenterBitmap, clockCenterSrc,

        clockCenterDst, null);

  if (mHelpBitmap ==null) {

mHelpBitmap = TimeSetActivity.helpNormalBitmap;

  }

// 画帮助按钮

  canvas.drawBitmap(mHelpBitmap, helpSrc, helpDst, null);

  // Paint paint = new Paint();

// paint.setColor(Color.RED);

  // // 画标准x y坐标辅助线

  // canvas.drawLine(0, standardY, canvas.getWidth(), standardY, paint);

// canvas.drawLine(standardX, 0, standardX, canvas.getHeight(), paint);

}

2. 绘制时针

private void drawHour(Canvas canvas) {

  canvas.save();

  canvas.translate(standardX, standardY);

  canvas.rotate(curTime.mHourDegree);

  Paintpaint =new Paint();

  paint.setAntiAlias(true);

  int height =this.mHourPressFlag ?mHourPressHeight :mHourNormalHeight;

  int width = (int) (height /10.5f);

  paint.setColor(Color.DKGRAY);

  hourRectF.left = -width /2;

  hourRectF.right =width /2;

  hourRectF.bottom =height *3.8f /5f;

  hourRectF.top = -height *1.2f /5f;

  canvas.drawRoundRect(hourRectF, 10, 10, paint);

  canvas.restore();

}

3. 绘制分针

public void drawMinute(Canvas canvas) {

  canvas.save();

  canvas.translate(standardX, standardY);

  canvas.rotate(curTime.mMinuteDegree);

  Paintpaint =new Paint();

  paint.setAntiAlias(true);

  int height =this.mMinutePressFlag ?mMinutePressHeight

        :mMinuteNormalHeight;

  int width = (int) (height /15.5f);

  paint.setColor(Color.DKGRAY);

  minuteRectF.left = -width /2;

  minuteRectF.right =width /2;

  minuteRectF.bottom =height *3.8f /5f;

  minuteRectF.top = -height *1.2f /5f;

  canvas.drawRoundRect(minuteRectF, 10, 10, paint);

  canvas.restore();

}

4. 命中区域判断

private boolean isHitArea(Point point) {

        boolean flag = !(point.x hitAreaXRight

        || point.y >hitAreaYTop || point.y

  if (!flag) {

      // 如果没有命中, 则设置标志位

      this.cursorHitStatus =0;

  }

return flag;

}

5.  时分触控及是否被选中

private void doTouchDownWork(Point point) {

   QuadranthandQuadant = ClockDegreeAdapter.getQuadrant(point);

    // 当前分针的象限

  QuadrantminuteQuadant = ClockDegreeAdapter

 .getQuadrant(curTime.mMinuteDegree);

  // 当前时针所在象限

  QuadranthourQuadant = ClockDegreeAdapter

 .getQuadrant(curTime.mHourDegree);

  // 如果当前的分针或分针在event所在象限, 则进行处理,

  // 如果时针和分针都在此象限, 则判断指针坐标与event靠近的那个进行重绘

  // 否则不进行处理

   cursorHitStatus =0;

  // 时针分针不在同一个象限

  if (minuteQuadant !=hourQuadant) {

       if (handQuadant ==minuteQuadant) {

        cursorHitStatus =1;

        setClockStatus(true, false, true);

      }else if (handQuadant ==hourQuadant) {

      setClockStatus(true, true, false);

        cursorHitStatus =2;

      }

}

// 如果在时针分针在同一个象限

  else if (minuteQuadant ==hourQuadant &&minuteQuadant ==handQuadant) {

      int eventRadian = ClockDegreeAdapter.getAngle(point);

      // 计算event与时针,分针的夹角的绝对值

      int minuteCrossRadian = Math.abs(eventRadian

            -curTime.mMinuteDegree);

      int hourCrossRadian = Math.abs(eventRadian -curTime.mHourDegree);

      // 比较夹角, 选择小的夹角的那个指针作为当前被重绘的对象

      if (hourCrossRadian=2)

        setClockStatus(true, true, false);

      }else {

        cursorHitStatus =1;

        setClockStatus(true, false, true);

      }

}

// 如果以上都没有命中, 则有可能指针在坐标轴上

 if (cursorHitStatus ==0) {

      // 可能是在坐标轴上

      int eventRadian = ClockDegreeAdapter.getAngle(point);

      if (curTime.mMinuteDegree %90 ==0) {

               if (Math.abs((eventRadian >=345 ?360 -eventRadian

              :eventRadian) -curTime.mMinuteDegree) <=15) {

            // 分针与event指针在15度范围内被选中

            cursorHitStatus =1;

            setClockStatus(true, false, true);

        }

}else if (curTime.mHourDegree %90 ==0) {

             int hourDegree =curTime.mHourDegree >=360 ?curTime.mHourDegree -360

              :curTime.mHourDegree;

        if (Math.abs((eventRadian >=345 ?360 -eventRadian

              :eventRadian) -hourDegree) <=15) {

          // 时针与event指针在15度范围内被选中

            cursorHitStatus =2;

            setClockStatus(true, true, false);

        }

}

}

}

6. Move时时分的计算

private void doTouchMoveWork(Point point) {

  int pointDegree = ClockDegreeAdapter.getAngle(point);

  if (cursorHitStatus ==1) {

      curTime.mMinuteDegree =pointDegree;

  }else if (cursorHitStatus ==2) {

      // 如果是时针的场合, 以上一次的时针跟本次时针的差额进行时间的选取

      int tempHourDegree =0;

      int minus = Math.abs(preHourDegree -pointDegree);

      if (minus <90) {

          tempHourDegree =pointDegree;

      }else if (minus >360

            && (pointDegree <90 && (preHourDegree <90 ||preHourDegree >600))) {

          tempHourDegree =0;

      }else {

tempHourDegree = (pointDegree +360) %980;

      }

curTime.mHourDegree =tempHourDegree;

      // 将上次数据保存

      preHourDegree =curTime.mHourDegree;

      // 24小时制的时间的角度为0~720度

      curTime.mHour = ClockDegreeAdapter.getHour(curTime.mHourDegree);

  }

}

7. onTouch的处理

@Override

public boolean onTouch(View v, MotionEvent event) {

Pointpoint =new Point();

  int eventX = (int) event.getX();

  int eventY = (int) event.getY();

  point.x =eventX -standardX;

  point.y =standardY -eventY;

  switch (event.getAction()) {

case MotionEvent.ACTION_DOWN:

if (eventX >=helpDst.left &&eventX <=helpDst.right

            &&eventY >=helpDst.top &&eventY <=helpDst.bottom) {

        // 该状态位为true的场景下, toutch up的时候, 打开question detai帮助页面

        helpHitFlag =true;

        mHelpBitmap = TimeSetActivity.helpPressBitmap;

        postInvalidate();

      }

if (isHitArea(point)) {

      // 只有在被命中区域才执行事件

        doTouchDownWork(point);

        calcDegree(point, false);

        postInvalidate();

      }

}

break;

  case MotionEvent.ACTION_MOVE:

doTouchMoveWork(point);

      // mClockBitmap = TimeSetActivity.clockPressBitmap;

      calcDegree(point, false);

      postInvalidate();

break;

  case MotionEvent.ACTION_UP:

// 松开手,无条件切换成帮助按钮的没有选中的状态

      mHelpBitmap = TimeSetActivity.helpNormalBitmap;

      mClockBitmap = TimeSetActivity.clockNormalBitmap;

      this.mHourPressFlag =false;

      this.mMinutePressFlag =false;

      calcDegree(point, true);

      postInvalidate();

break;

  }

return true;

}

8. 获取时分所在的弧度

private static double getRadianByPosEx(Point point) {

if (point.x ==0 && point.y ==0) {

return 0;

  }

double Sin = Math.abs(point.x)

/ Math.sqrt(point.x * point.x + point.y * point.y);

  double dAngle = Math.asin(Sin);

  switch (getQuadrant(point)) {

case EQ_NONE: {

if (point.x ==0 && point.y ==0) {

return 0;

      }

if (point.x ==0) {

if (point.y >0) {

return PI;

        }else {

return 0;

        }

}

if (point.y ==0) {

if (point.x >0) {

return (float) (1.5 *PI);

        }else {

return PI /2;

        }

}

}

break;

  case EQ_ONE: {

return PI +dAngle;

  }

case EQ_TWO: {

return PI -dAngle;

  }

case EQ_THREE: {

return dAngle;

  }

case EQ_FOUR: {

return 2 *PI -dAngle;

  }

}

return 0;

}

9. 获取点所在的角度及对应的分钟数,小时数

public static int getAngle(Point point) {

double dAngle =getRadianByPosEx(point);

  return (int) (dAngle * (360 / (2 *PI)));

}

public static int getMinute(int angle) {

return (angle /6 +30) %60;

}

public static int getHour(int angle) {

if (angle <540) {

return 6 + angle /30;

  }else {

return (angle -540) /30;

  }

}

10. 返回时针校验角度

public static int getUnionHourAngle(int hour24, int minute) {

int hourDegreePlus = minute /2;

  int hour = hour24 >12 ? hour24 -12 : hour24;

  hour =hour <6 ?12 +hour :hour;

  // if (hour24 >= 18 || hour24 <= 5) {

// return (hour - 6) * 30 + +360 + hourDegreePlus;

// }

  return (hour -6) *30 +hourDegreePlus;

}

上一篇下一篇

猜你喜欢

热点阅读