美文网首页
Android自定义view 时钟的绘制

Android自定义view 时钟的绘制

作者: 宝马奔驰_xyz | 来源:发表于2018-11-09 17:33 被阅读19次

    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;

    }

    相关文章

      网友评论

          本文标题:Android自定义view 时钟的绘制

          本文链接:https://www.haomeiwen.com/subject/ayboxqtx.html