Android 自定义 View--> 绘制时钟(表)效果

Posted Kevin-Dev

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 自定义 View--> 绘制时钟(表)效果相关的知识,希望对你有一定的参考价值。

前言

本篇文章主要介绍使用自定义 View 来实现时钟效果,灵活地使用 androidCanvasPaint, Path 的 API 以及理清 Canvassaverestore 的意义。

代码实现

1. 新建一个类继承 View

public class ClockView extends View 
    //原点
    private Point mCoo = new Point(500, 800);
    private Path mMainPath;
    private Paint mMainPaint;
    
    public ClockView(Context context) 
        this(context,null);
    

    public ClockView(Context context, @Nullable AttributeSet attrs) 
        super(context, attrs);

        init();
    

    private void init() 
        //初始化画笔
        mMainPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mMainPaint.setStyle(Paint.Style.STROKE);
        mMainPaint.setStrokeCap(Paint.Cap.ROUND);

        mMainPath = new Path();
        
    

    @Override
    protected void onDraw(Canvas canvas) 
        super.onDraw(canvas);
        //绘制
        canvas.save();//新建图层1
        canvas.translate(mCoo.x, mCoo.y);

        drawBreakCircle(canvas);
        drawDot(canvas);
        drawText(canvas);

        Calendar calendar = Calendar.getInstance();
        int hour = calendar.get(Calendar.HOUR_OF_DAY);
        int min = calendar.get(Calendar.MINUTE);
        int sec = calendar.get(Calendar.SECOND);

        drawH(canvas, hour / 12.f * 360 - 90 + min / 60.f * 30 + sec / 3600.f * 30);
        drawM(canvas, min / 60.f * 360 - 90 + sec / 60.f);
        drawS(canvas, sec / 60.f * 360 - 90);
        canvas.restore();
    
 

2. 绘制逻辑

2.1 绘制破碎的圆

	/**
     * 绘制破碎的圆
     *
     * @param canvas
     */
    private void drawBreakCircle(Canvas canvas) 
        mMainPaint.setStrokeWidth(8);
        mMainPaint.setColor(Color.parseColor("#D5D5D5"));

        for (int i = 0; i < 4; i++) 
            canvas.save();
            canvas.rotate(90 * i);
            canvas.drawArc(
                    -350, -350, 350, 350,
                    10, 70, false, mMainPaint);
            canvas.restore();
        
    

2.2 绘制小点
画 60 个点(小线),每逢 5 变长,也就是画直线,每次将画布旋转 360 / 60 = 6°

	/**
     * 绘制小点
     *
     * @param canvas
     */
    private void drawDot(Canvas canvas) 
        for (int i = 0; i < 60; i++) 
            if (i % 5 == 0) 
                canvas.save();
                canvas.rotate(30 * i);
                mMainPaint.setStrokeWidth(8);
                mMainPaint.setColor(randomRGB());
                canvas.drawLine(250, 0, 300, 0, mMainPaint);

                mMainPaint.setStrokeWidth(10);
                mMainPaint.setColor(Color.BLACK);
                canvas.drawPoint(250, 0, mMainPaint);
                canvas.restore();
             else 
                canvas.save();
                canvas.rotate(6 * i);
                mMainPaint.setStrokeWidth(4);
                mMainPaint.setColor(Color.BLUE);
                canvas.drawLine(280, 0, 300, 0, mMainPaint);
                canvas.restore();
            
        
    
	/**
     * 返回随机颜色
     *
     * @return 随机颜色
     */
    public static int randomRGB() 
        Random random = new Random();
        int r = 30 + random.nextInt(200);
        int g = 30 + random.nextInt(200);
        int b = 30 + random.nextInt(200);
        return Color.rgb( r, g, b);
    

2.3 绘制文字

/**
     * 添加文字
     *
     * @param canvas
     */
    private void drawText(Canvas canvas) 
        mMainPaint.setTextSize(60);
        mMainPaint.setStrokeWidth(5);
        mMainPaint.setStyle(Paint.Style.FILL);
        mMainPaint.setTextAlign(Paint.Align.CENTER);
        mMainPaint.setColor(Color.BLUE);
        canvas.drawText("Ⅲ", 350, 30, mMainPaint);
        canvas.drawText("Ⅵ", 0, 350 + 30, mMainPaint);
        canvas.drawText("Ⅸ", -350, 30, mMainPaint);
        canvas.drawText("Ⅻ", 0, -350 + 30, mMainPaint);

        //使用外置字体放在assets目录下
        Typeface myFont = Typeface.createFromAsset(getContext().getAssets(), "CHOPS.TTF");
        mMainPaint.setTypeface(myFont);
        mMainPaint.setTextSize(70);
        canvas.drawText("Kevin", 0, -150, mMainPaint);
    

tips:
.ttf 字体文件下载地址:https://www.fonts.net.cn/

2.4 绘制时针

	/**
     * 绘制时针
     *
     * @param canvas
     * @param deg
     */
    private void drawH(Canvas canvas, float deg) 
        canvas.save();
        canvas.rotate(deg);
        mMainPaint.setColor(Color.BLACK);
        mMainPaint.setStrokeCap(Paint.Cap.ROUND);

        mMainPaint.setStrokeWidth(8);
        canvas.drawLine(0, 0, 150, 0, mMainPaint);
        canvas.restore();
    

2.5 绘制分针

	/**
     * 绘制分针
     *
     * @param canvas
     * @param deg
     */
    private void drawM(Canvas canvas, float deg) 
        canvas.save();
        canvas.rotate(deg);
        mMainPaint.setColor(Color.BLACK);
        mMainPaint.setStrokeWidth(8);
        canvas.drawLine(0, 0, 200, 0, mMainPaint);

        mMainPaint.setColor(Color.GRAY);
        mMainPaint.setStrokeWidth(30);
        canvas.drawPoint(0, 0, mMainPaint);
        canvas.restore();
    

2.6 绘制秒针

	/**
     * 绘制秒针
     *
     * @param canvas
     * @param deg
     */
    private void drawS(Canvas canvas, float deg) 
        mMainPaint.setStyle(Paint.Style.STROKE);
        mMainPaint.setColor(Color.RED);
        mMainPaint.setStrokeWidth(8);
        mMainPaint.setStrokeCap(Paint.Cap.SQUARE);

        canvas.save();
        canvas.rotate(deg);

        canvas.save();
        canvas.rotate(45);
        //使用path绘制:在init里初始化一下就行了
        mMainPath.addArc(-25, -25, 25, 25, 0, 240);
        canvas.drawPath(mMainPath, mMainPaint);
        canvas.restore();

        mMainPaint.setStrokeCap(Paint.Cap.ROUND);
        canvas.drawLine(-25, 0, -50, 0, mMainPaint);

        mMainPaint.setStrokeWidth(2);
        mMainPaint.setColor(Color.RED);
        canvas.drawLine(0, 0, 320, 0, mMainPaint);

        mMainPaint.setStrokeWidth(15);
        mMainPaint.setColor(Color.RED);
        canvas.drawPoint(0, 0, mMainPaint);
        canvas.restore();
    

让时钟动起来

1. 布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/white"
    android:orientation="vertical"
    tools:context=".ParcticeOneActivity">

    <com.kjd.gesturedemo.widget.ClockView
        android:id="@+id/clockView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</LinearLayout>

2. 更新时间

public class ParcticeOneActivity extends AppCompatActivity 

    /**
     * 新建Handler
     */
    Handler mHandler = new Handler() 
        @Override
        public void handleMessage(Message msg) 
            mView.invalidate();//处理:刷新视图
        
    ;

    private View mView;
    private final Timer timer = new Timer();

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_parctice_one);

        mView = findViewById(R.id.clockView);

        TimerTask timerTask = new TimerTask() 
            @Override
            public void run() 
                mHandler.sendEmptyMessage(0);//发送消息
            
        ;
        //定时任务
        timer.schedule(timerTask, 0, 1000);
    

    public void clicked(View view) 
        new HighLightView(this).showTipForView(view, "", new View.OnClickListener() 
            @Override
            public void onClick(View v) 

            
        );
    

以上是关于Android 自定义 View--> 绘制时钟(表)效果的主要内容,如果未能解决你的问题,请参考以下文章

Android 自定义时钟控件 时针分针秒针的绘制这一篇就够了

android绘制时钟,canvas学习

android绘制时钟,canvas学习

Android自定义View初步

仿照爱时间app写的时钟 自定义view

仿照爱时间app写的时钟 自定义view