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

前言

本篇文章主要介绍使用自定义 View 来实现时钟效果,灵活地使用 Android 的 CanvasPaint, 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) {

            }
        });
    }
}
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Kevin-Dev

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值