android 自定义时钟圆盘

先来一个效果图

 

先建一个类 继承自 View 重写 View(Context context, @Nullable AttributeSet attrs)方法,在次方法中初始化画笔工具与时间

private void initPaint() {
    paint =new Paint();
    paint.setAntiAlias(true);
    paint.setStrokeWidth(1);
    paint.setStrokeJoin(Paint.Join.ROUND);
    paint.setStrokeCap(Paint.Cap.ROUND);
    paint.setColor(Color.parseColor("#12ff46"));
    mCalendar=Calendar.getInstance();
}

设置计时器,定时刷新View

new Timer().scheduleAtFixedRate(new TimerTask() {
    @Override
    public void run() {
        invalidate();
    }
},0,1000);

根据界面的宽高以中心点为圆点,设置合理的半径画圆

int w=getWidth();
int h=getHeight();
r=w/2-60;
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(15);
canvas.drawCircle(w/2,h/2,r, paint);//时钟圆盘
paint.setStyle(Paint.Style.FILL);
canvas.drawCircle(w/2,h/2,20, paint);//中心小圆覆盖点

为了美观在中心点画一个小圆(此效果可以放到最后画,用以覆盖时针,分针,秒针在中心位置的交叉点)

然后画12至11的刻度(1-12),flow是角度的偏移量,取值 Math.PI,然后画各时刻之间的分钟标记,以及时刻的数字

        for(int i=0;i<hours.length;i++){
            paint.setStrokeWidth(15);
            tx=(w/2+(float)Math.sin(-Math.PI*30*i/180+flow)*(r-indicatorSize));
            ty= (h/2+(float)Math.cos(-Math.PI*30*i/180+flow)*(r-indicatorSize));
            sx=(float)(w/2+Math.ceil(Math.sin(-Math.PI*30*i/180+flow)*r));
            sy=(float)(h/2+Math.ceil(Math.cos(-Math.PI*30*i/180+flow)*r) );
            //小时刻度点
            canvas.drawLine(tx,ty,sx,sy, paint);
//            //时钟中心点与小时刻度点的连接线
//            paint.setStrokeWidth(1);
//            canvas.drawLine(w/2,h/2,sx,sy,paint);
            paint.setStrokeWidth(5);
            for(int j=0;j<5;j++){
                tx=(w/2+(float)Math.sin(-Math.PI*(30*i+j*6)/180+flow)*(r-indicatorSize/2));
                ty= (h/2+(float)Math.cos(-Math.PI*(30*i+j*6)/180+flow)*(r-indicatorSize/2));
                sx=(float)(w/2+Math.ceil(Math.sin(-Math.PI*(30*i+j*6)/180+flow)*r));
                sy=(float)(h/2+Math.ceil(Math.cos(-Math.PI*(30*i+j*6)/180+flow)*r) );
                //分钟/秒针刻度点
                paint.setStrokeWidth(5);
                canvas.drawLine(tx,ty,sx,sy, paint);
//                //时钟中心点与分钟/秒刻度点的连接线
//                paint.setStrokeWidth(1);
//                canvas.drawLine(w/2,h/2,sx,sy,paint);
            }
            paint.setStrokeWidth(1);
            tx=(float)(w/2+Math.sin(-Math.PI*30*i/180+flow)*(r-60));
            ty=(float) (h/2+Math.cos(-Math.PI*30*i/180+flow)*(r-60));
            paint.setStrokeWidth(1);
            paint.setTextSize(40);
            canvas.drawText(hours[i],tx- paint.measureText(hours[i])/2,ty+ paint.getTextSize()/2, paint);
        }

获取当前时间

//获取当前时间
mCalendar.setTimeInMillis(System.currentTimeMillis());
ho=mCalendar.get(Calendar.HOUR);
m=mCalendar.get(Calendar.MINUTE);
s=mCalendar.get(Calendar.SECOND);

将时分秒画到界面上

//时针
paint.setStrokeWidth(20);
canvas.drawLine(w/2,h/2,(float)(w/2+Math.sin(-(Math.PI*30*(ho+m/60f))/180+flow)*(r*5f/12)),
        (float) (h/2+Math.cos(-(Math.PI*30*(ho+m/60f))/180+flow)*(r*5f/12)), paint);
//分针
paint.setStrokeWidth(10);
canvas.drawLine(w/2,h/2,(float)(w/2+Math.sin(-(Math.PI*6*(m+s/60f))/180+flow)*(r*7f/12)),
        (float) (h/2+Math.cos(-(Math.PI*6*(m+s/60f))/180+flow)*(r*7f/12)), paint);
//秒针
paint.setStrokeWidth(5);
canvas.drawLine(w/2,h/2,(float)(w/2+Math.sin(-(Math.PI*6*s)/180+flow)*(r*17f/24)),
        (float) (h/2+Math.cos(-(Math.PI*6*s)/180+flow)*(r*17f/24)), paint);

然后画时钟顶部的小部件

//顶部小部件
paint.setStrokeWidth(20);
canvas.drawLine(w/2,h/2-r,w/2,h/2-r-40, paint);
canvas.drawLine(w/2-60,h/2-r-40,w/2+60,h/2-r-40, paint);

然后可以画内部右侧的年月日

paint.setStrokeWidth(2);
paint.setTextSize(35);
paint.setStyle(Paint.Style.FILL);
String p=getNumberS(mCalendar.get(Calendar.YEAR))
        +" - "+getNumberS(mCalendar.get(Calendar.MONTH)+1)
        +" - "+getNumberS(mCalendar.get(Calendar.DATE));
canvas.drawText(p,w/2+r/3,h/2+paint.getTextSize()/2,paint);
private String getNumberS(int n){
    if(n>=10){
        return n+"";
    }else {
        return "0"+n;
    }
}

下面是整个自定义View的代码,为了代码的简洁 -(Math.PI*6*(m+s/60f))/180+flow 此类计算在代码中用 angle 替换了,上面的各代码片段为了描述具体的计算方式未规整

package com.dalor.drawcanvas;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;

import java.util.*;

/**
 * 作者: 吴昶 .
 * 时间: 2019/1/10 16:29
 * 功能简介:
 */
public class DrawTestView extends View {

    private Paint paint;
    private float r=60;//圆半径
    private double flow=Math.PI;//偏差角度
    private int indicatorSize=20;//小刻度基准长度
    private String[] hours=new String[]{"12","1","2","3","4","5","6","7","8","9","10","11"};
    private Calendar mCalendar;
    private float tx;//线点
    private float ty;
    private float sx;//线点
    private float sy;
    private int ho;//小时
    private int m;//分钟
    private int s;//秒数
    private double angle;//各时刻对应的角度

    public DrawTestView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        initPaint();
        //计时器,每秒钟刷新一次界面
        new Timer().scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                invalidate();
            }
        },0,1000);
    }

    private void initPaint() {
        paint =new Paint();
        paint.setAntiAlias(true);
        paint.setStrokeWidth(1);
        paint.setStrokeJoin(Paint.Join.ROUND);
        paint.setStrokeCap(Paint.Cap.ROUND);
        paint.setColor(Color.parseColor("#12ff46"));
        mCalendar=Calendar.getInstance();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int w=getWidth();
        int h=getHeight();
        r=w/2-60;
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(15);
        canvas.drawCircle(w/2,h/2,r, paint);//时钟圆盘
        paint.setStyle(Paint.Style.FILL);
        canvas.drawCircle(w/2,h/2,20, paint);//中心小圆覆盖点
        paint.setStyle(Paint.Style.STROKE);
        for(int i=0;i<hours.length;i++){
            paint.setStrokeWidth(15);
            angle=-Math.PI*30*i/180+flow;
            tx=(w/2+(float)Math.sin(angle)*(r-indicatorSize));
            ty= (h/2+(float)Math.cos(angle)*(r-indicatorSize));
            sx=(float)(w/2+Math.ceil(Math.sin(angle)*r));
            sy=(float)(h/2+Math.ceil(Math.cos(angle)*r) );
            //小时刻度点
            canvas.drawLine(tx,ty,sx,sy, paint);
            //时钟中心点与小时刻度点的连接线
//            paint.setStrokeWidth(1);
//            canvas.drawLine(w/2,h/2,sx,sy,paint);
            paint.setStrokeWidth(5);
            for(int j=0;j<5;j++){
                angle=-Math.PI*(30*i+j*6)/180+flow;
                tx=(w/2+(float)Math.sin(angle)*(r-indicatorSize/2));
                ty= (h/2+(float)Math.cos(angle)*(r-indicatorSize/2));
                sx=(float)(w/2+Math.ceil(Math.sin(angle)*r));
                sy=(float)(h/2+Math.ceil(Math.cos(angle)*r) );
                //分钟/秒针刻度点
                paint.setStrokeWidth(5);
                canvas.drawLine(tx,ty,sx,sy, paint);
                //时钟中心点与分钟/秒刻度点的连接线
//                paint.setStrokeWidth(1);
//                canvas.drawLine(w/2,h/2,sx,sy,paint);
            }
            paint.setStrokeWidth(1);
            angle=-Math.PI*30*i/180+flow;
            tx=(float)(w/2+Math.sin(angle)*(r-60));
            ty=(float) (h/2+Math.cos(angle)*(r-60));
            paint.setStrokeWidth(1);
            paint.setTextSize(40);
            canvas.drawText(hours[i],tx- paint.measureText(hours[i])/2,ty+ paint.getTextSize()/2, paint);
        }
        //获取当前时间
        mCalendar.setTimeInMillis(System.currentTimeMillis());
        ho=mCalendar.get(Calendar.HOUR);
        m=mCalendar.get(Calendar.MINUTE);
        s=mCalendar.get(Calendar.SECOND);
        //时针
        paint.setStrokeWidth(20);
        angle=-(Math.PI*30*(ho+m/60f))/180+flow;
        canvas.drawLine(w/2,h/2,(float)(w/2+Math.sin(angle)*(r*5f/12)),
                (float) (h/2+Math.cos(angle)*(r*5f/12)), paint);
        //分针
        paint.setStrokeWidth(10);
        angle=-(Math.PI*6*(m+s/60f))/180+flow;
        canvas.drawLine(w/2,h/2,(float)(w/2+Math.sin(angle)*(r*7f/12)),
                (float) (h/2+Math.cos(angle)*(r*7f/12)), paint);
        //秒针
        paint.setStrokeWidth(5);
        angle=-(Math.PI*6*s)/180+flow;
        canvas.drawLine(w/2,h/2,(float)(w/2+Math.sin(angle)*(r*17f/24)),
                (float) (h/2+Math.cos(angle)*(r*17f/24)), paint);

        //顶部小部件
        paint.setStrokeWidth(20);
        canvas.drawLine(w/2,h/2-r,w/2,h/2-r-40, paint);
        canvas.drawLine(w/2-60,h/2-r-40,w/2+60,h/2-r-40, paint);

        //时钟内部右侧时间展示
        paint.setStrokeWidth(2);
        paint.setTextSize(35);
        paint.setStyle(Paint.Style.FILL);
        String p=getNumberS(mCalendar.get(Calendar.YEAR))
                +" - "+getNumberS(mCalendar.get(Calendar.MONTH)+1)
                +" - "+getNumberS(mCalendar.get(Calendar.DATE));
        canvas.drawText(p,w/2+r/3,h/2+paint.getTextSize()/2,paint);
    }

    private String getNumberS(int n){
        if(n>=10){
            return n+"";
        }else {
            return "0"+n;
        }
    }
}

上面的代码未对控件的宽高做大小判断,使用时请注意横竖屏的问题,可能会出现界面显示不全的问题。

上面的代码已屏蔽刻度线。

使用方式,在布局文件中直接引入

<com.dalor.drawcanvas.DrawTestView
        android:id="@+id/dtv_test"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

猜你喜欢

转载自blog.csdn.net/weixin_41191134/article/details/86299868