自定义 view 时钟

891 阅读2分钟
原文链接: www.jianshu.com

效果


clockview.gif

思路

  1. 先绘制刻度和文字,通过旋转画布来操作

    //移动画布到屏幕正中间
        canvas.translate(getMeasuredWidth() / 2, getMeasuredHeight() / 2);
        //当前数字
        int currentP = 0;
        //绘制的数字
        String text = "";
        int len;
        for (int i = 0; i < 360 / fixAngle; i++) {
            if (i % 5 == 0) {
                if (currentP == 0) {
                    text = "12";
                } else {
                    text = currentP + "";
                }
                currentP++;
                mArcPaint.setColor(Color.BLUE);
                mArcPaint.setTextSize(40);
                mArcPaint.getTextBounds(text, 0, text.length(), mTextBound);
                canvas.drawText(text, 0, text.length(), -mTextBound.width() / 2, -(radius + b_len + 20), mArcPaint);
    
                mArcPaint.setColor(Color.RED);
                len = b_len;
    
            } else {
                mArcPaint.setColor(Color.GREEN);
                len = s_len;
            }
            canvas.drawLine(0, -radius, 0, -(radius + len), mArcPaint);
            canvas.rotate(fixAngle);
        }
  2. 绘制指针

    /**
      * 画秒针
      * @param canvas
      */
     private void drawS(Canvas canvas) {
    
         double angle = (s * fixAngle - 90)*Math.PI/180;
         int mSecondLen = 280;
         int startX = -(int) (len * Math.cos(angle));
         int startY = -(int) (len * Math.sin(angle));
    
         int endX = (int) ((mSecondLen - len) * Math.cos(angle));
         int endY = (int) ((mSecondLen - len) * Math.sin(angle));
         canvas.drawLine(startX, startY, endX, endY, sPaint);
    
     }
    
     /**
      * 画分针
      * @param canvas
      */
     private void drawM(Canvas canvas) {
         double angle = (m * 6 - 90)*Math.PI/180;
         int mMinLen = 250;
         int startX = -(int) (len * Math.cos(angle));
         int startY = -(int) (len * Math.sin(angle));
    
         int endX = (int) ((mMinLen - len) * Math.cos(angle));
         int endY = (int) ((mMinLen - len) * Math.sin(angle));
         canvas.drawLine(startX, startY, endX, endY, minPaint);
     }
    
     /**
      * 画时针
      * @param canvas
      */
     private void drawH(Canvas canvas) {
    
         double angle = (h * 6 * 5 - 90)*Math.PI/180+((m *1.0f/60 *30)*Math.PI/180);
         int mHourLen = 230;
         int startX = -(int) (len * Math.cos(angle));
         int startY = -(int) (len * Math.sin(angle));
    
         int endX = (int) ((mHourLen - len) * Math.cos(angle));
         int endY = (int) ((mHourLen - len) * Math.sin(angle));
         canvas.drawLine(startX, startY, endX, endY, hPaint);
     }
  3. 绘制中心原点
    private void drawPoint(Canvas canvas) {
         mArcPaint.setColor(Color.WHITE);
         canvas.drawCircle(0, 0, 10, mArcPaint);
     }

遇到的问题

怎么实时刷新时间 让指针转起来?

方案一

  1. 继承自View
  2. 开线程,添加一个循环,然后通过handler 去调用invalidate()

结果:打开界面几秒后 app 直接崩溃

方案二

  1. 继承自View
  2. onDraw()内加入以下代码

    @Override
     protected void onDraw(Canvas canvas) {
         .....
    
         postInvalidateDelayed(1000);
         invalidate();
     }

结果:其实就是一个死循环,效果是出来了,但是内存抖动特别厉害,频繁的触发GC


Paste_Image.png

方案三

  1. 继承子 SurfaceView
  2. 缓存一个图层

    private void drawUI() {
         try {
             canvas = mSurfaceHolder.lockCanvas();
             //缓存一个图层
             if (bitmapCache == null) {
                 bitmapCache = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Bitmap.Config.ARGB_4444);
             }
             canvas1 = new Canvas(bitmapCache);
             canvas1.drawColor(Color.BLACK);
             drawCanvas(canvas1);
             canvas.drawBitmap(bitmapCache, 0, 0, mPaint);
         } catch (Exception e) {
             e.printStackTrace();
         } finally {
             try {
                 mSurfaceHolder.unlockCanvasAndPost(canvas);
             } catch (Exception e) {
                 e.printStackTrace();
             }
         }
     }

结果:实现效果,内存也还比较稳定


Paste_Image.png

代码地址

github.com/FeeAlan/Clo…