仿小米时钟-简约版

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_34975710/article/details/73844816
小米的UI相对来说是做的很美观的,这里就简单的模仿一下小米的时钟,上面部分效果没有加上,先看下效果图:

这里写图片描述

下面是小米的UI:

这里写图片描述
去实现这个效果其实只需要分为三个步骤就可以了:
1、画最外围的圆弧、数字
2、画刻度线
3、画时针、分针、秒针

整个View的一些属性,如颜色、背景等等可以使用自定义属性进行设置增加其灵活性,这里为了简单就直接在代码中设置了。这里只是大致的思路,没有贴出全部代码。基本的工作就不做多的介绍,这里创建一个类ClockView继承View,初始化各个Paint、设置属性、各个坐标的变量等等。

1、画最外围的圆弧、数字

这里写图片描述
首先定义一个RectF确定圆弧的区域:

        // 设置圆弧绘制区域
        float left = (float) (clockX - 1.2 * radius);// 根据原点的中心左边和刻度线的半径
        float top = (float) (clockY - 1.2 * radius);
        float right = (float) (clockX + 1.2 * radius);
        float bottom = (float) (clockY + 1.2 * radius);
        RectF rect = new RectF(left,top,right,bottom);

这里的难点是文字的绘制,文字其实也是一块矩形区域,它的锚点在左下角,所以绘制文字时为了在弧线的中间要注意锚点的坐标,以右边的“3”为例,绿线是圆弧区域的右边界,它的X坐标是已经定义好的–right,那现在只需要知道“3”文字的宽度textWidth,拿right减去textWidth/2正好就是锚点的X坐标。在水平方向也是居中的,那只需要用圆心的y坐标clockY加上文字高度的一半,文字高度是自己设定的,参考下面的示意图,剩下的“6”、“9”、“12”以此类推:
这里写图片描述

 private void drawArcLines(Canvas canvas) {
        // 设置圆弧绘制区域
        float left = (float) (clockX - 1.2 * radius);// 根据原点的中心左边和刻度线的半径
        float top = (float) (clockY - 1.2 * radius);
        float right = (float) (clockX + 1.2 * radius);
        float bottom = (float) (clockY + 1.2 * radius);
        RectF rect = new RectF(left,top,right,bottom);

        // 圆弧设置
        arcPaint.setStyle(Paint.Style.STROKE);
        arcPaint.setStrokeWidth(1);
        arcPaint.setARGB(125, 255, 255, 255);
        // 字体设置
        textPaint.setTextSize(40);
        textPaint.setARGB(125, 255, 255, 255);

        String num = "0";
        // 文字的坐标
        float textX = 0;
        float textY = 0;
        float textWidth = 0;
        // 通过循环,每90度绘制以此圆弧和文字
        for (int i = 0; i < 360; i += 90) {
            // 画圆弧,注意圆弧的起始终止弧度,留一定的间隙给文字
            canvas.drawArc(rect, 5 + i, 80, false, arcPaint);
            // 计算文字锚点坐标
            switch (i) {
                case 0:
                    num = "3";
                    textWidth = textPaint.measureText(num);
                    textX = right - textWidth / 2;
                    textY = clockY + 10;
                    break;
                case 90:
                    num = "6";
                    textWidth = textPaint.measureText(num);
                    textX = clockX - textWidth / 2;
                    textY = bottom + 10;
                    break;
                case 180:
                    num = "9";
                    textWidth = textPaint.measureText(num);
                    textX = left - textWidth / 2;
                    textY = clockY + 10;
                    break;
                case 270:
                    num = "12";
                    textWidth = textPaint.measureText(num);
                    textX = clockX - textWidth / 2;
                    textY = top + 10;
                    break;
            }
            // 绘制文字
            canvas.drawText(num, textX, textY, textPaint);
        }
    }

2、画刻度线

画刻度线相对来说比较简单,知道刻度线的其实终止点坐标,例如下面的示意图,起始点a的想x、y坐标可以利用绿色圆形的半径乘以对应的三角函数,绿色圆形的半径radius可以直接根据屏幕的大小设定,这里不做解释了,终止点的坐标那就是粉色圆形的半径乘以三角函数,粉色圆形半径则可以设置成radius的百分之多少。计算的结果必须加上相应圆形的x或y坐标,这样才是真正相对于界面的坐标值。
知道怎么画一条之后,这一圈的刻度线就可以利用循环绘制,画多少条则根据每一条间隔的角度可以设定。、

// 画短线
    private void drawShortLines(Canvas canvas) {
        paint.setStrokeWidth(4);
        for (double i = 0; i < 2 * PI; i += PI / 60) {
            float startX = (float) (radius * Math.cos(i)) + clockX;
            float startY = (float) (radius * Math.sin(i)) + clockY;
            float endX = (float) (0.85 * radius * Math.cos(i)) + clockX;
            float endY = (float) (0.85 * radius * Math.sin(i)) + clockY;
            paint.setARGB(125, 255, 255, 255);
            canvas.drawLine(startX, startY, endX, endY, paint);
        }
    }

这里写图片描述

3、画时针、分针、秒针

画这几个指针的思路是一样的,通过路径Path进行绘制
1、秒针
用 Path 绘制一个指向 12点钟 的三角形,通过不断旋转画布实现秒针的旋转:
三个点的坐标需要自己去调整

 private void drawSecPath(Canvas canvas){
        secPaint.setARGB(255,255,255,255);
        canvas.save();
        canvas.rotate(secDregee,clockX,clockY);// 旋转该层画布
        float offset =  radius * 0.15f;
        secPath.moveTo(clockX, clockY - 0.8f * radius);
        secPath.lineTo(clockX + offset / 2,clockY - 0.8f * radius + 0.86f * offset);
        secPath.lineTo(clockX - offset / 2,clockY - 0.8f * radius + 0.86f * offset);
        secPath.close();
        canvas.drawPath(secPath,secPaint);
        canvas.restore();
    }

这里写图片描述
2、分针
分针可以看做是一个梯形,同样用路径Path绘制:

 private void drawMinHand(Canvas canvas){
        minPaint.setARGB(200,255,255,255);
        canvas.save();
        canvas.rotate(minDregee,clockX,clockY);
        minPath.moveTo(clockX - 0.02f * radius,clockY - 0.1f * radius);
        minPath.lineTo(clockX - 0.01f * radius,clockY - 0.7f * radius);
        minPath.lineTo(clockX + 0.01f * radius,clockY - 0.7f * radius);
        minPath.lineTo(clockX + 0.02f * radius,clockY - 0.1f * radius);
        minPath.close();
        canvas.drawPath(minPath,minPaint);
        canvas.restore();
    }

2、时针
时针也可以看做是一个梯形,同样用路径Path绘制:

 private void drawHourHand(Canvas canvas){
        hourPaint.setARGB(255,255,255,255);
        canvas.save();
        canvas.rotate(hourDregee,clockX,clockY);
        hourPath.moveTo(clockX - 0.03f * radius,clockY - 0.06f * radius);
        hourPath.lineTo(clockX - 0.02f * radius,clockY - 0.6f * radius);
        hourPath.lineTo(clockX + 0.02f * radius,clockY - 0.6f * radius);
        hourPath.lineTo(clockX + 0.03f * radius,clockY - 0.06f * radius);
        hourPath.close();
        canvas.drawPath(hourPath,hourPaint);
}

这里写图片描述
在中间还有一个圆环,直接画一个空心圆并设置一些线条的宽度即可:

 private void drawCoverCircel(Canvas canvas) {
        circlePaint.setColor(Color.WHITE);
        circlePaint.setStyle(Paint.Style.STROKE);
        circlePaint.setStrokeWidth(0.06f * radius);
        canvas.drawArc(clockX - 0.08f * radius,clockY - 0.08f * radius,
                clockX + 0.08f * radius,clockY + 0.08f * radius,
                0f,360f,false,circlePaint);
    }

最终效果:
这里写图片描述

到这里所有的图形已绘制完毕,现在则需要让时分秒针动起来,在这三个绘制的方法中都有一个旋转的画布的方法,其中第一个参数就是指定画布旋转的角度,只要不断的改变其参数值就可让时分秒针动起来,这里在定义一个方法,将系统时间换算成时分秒针对应的旋转角度:

private void getTime(){
        Calendar calendar = Calendar.getInstance();

        float milliSecond = calendar.get(Calendar.MILLISECOND);
        // 在时分秒后面加上分、秒、毫秒,可以让指针旋转更加平滑,减少顿挫感
        float second = calendar.get(Calendar.SECOND) + milliSecond / 1000;
        float min = calendar.get(Calendar.MINUTE) + second / 60;
        float hour = calendar.get(Calendar.HOUR) + min / 60;
        // 角度换算
        secDregee = second / 60 * 360 ;
        minDregee = min / 60 * 360;
        hourDregee = hour / 12 * 360;
    }

最终的onDraw方法如下:

protected void onDraw(final Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawARGB(255, 40, 120, 200);
        getTime();
        drawArcLines(canvas);
        drawShortLines(canvas);
        drawSecPath(canvas);
        drawMinHand(canvas);
        drawHourHand(canvas);
        drawCoverCircel(canvas);
        // 在主线程调用界面刷新,刷新时调用onDraw方法,循环往复
        invalidate();
    }

好了,到这里整个流程已经结束,现在这个ClockView就可以在布局文件中直接使用了:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#123"
    android:orientation="vertical"
    tools:context="com.hqyj.clockview.MainActivity">

    <com.hqyj.clockview.ClockView
        android:layout_gravity="center_horizontal"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/clockView" />

</LinearLayout>

生活不只是敲代码,如果你或你身边的人喜欢摄影或者生活的点点滴滴,可以关注下我亲爱的公众号~
这里写图片描述

猜你喜欢

转载自blog.csdn.net/qq_34975710/article/details/73844816
今日推荐