Android自定义控件实现时钟

Android自定义控件实现时钟

建立一个自定义View,需要继承于View类,并且实现其构造函数和两个方法:onMeasure()和onDraw();
onMeasure();用于设置自定义View的尺寸
onDraw();用于绘制View中的内容。
一个自定义时钟的Demo:
自定义控件

package com.ben.test;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.View;

import java.util.Calendar;

/**
 * 时钟草稿
 */
public class ClockView extends View {
	//背景画笔
    private Paint mBackgroundPaint;
    //刻度线
    private Paint mScaleLinePaint;
    private Paint mHourPaint;
    private Paint mMinutePaint;
    private Paint mSecondPaint;
    //半径
    private int mRadius;
    //中心坐标
    private int mCenterX;
    private int mCenterY;
    private Handler mMainHandler;
    private int mClockBgColor;
    private int mBigScaleLineColor;
    private int mSmallScaleLineColor;
    private int mHourHandColor;
    private int mMinuteHandColor;
    private int mSecondHandColor;

    public ClockView(Context context) {
        this(context, null);
    }

    public ClockView(Context context, AttributeSet attrs) {//构造方法
        this(context, attrs, 0);
    }

    public ClockView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs);
    }

    private void init(Context context, AttributeSet attrs) {
        mBackgroundPaint = new Paint();//实例化画笔
        mScaleLinePaint = new Paint();
        mHourPaint = new Paint();
        mMinutePaint = new Paint();
        mSecondPaint = new Paint();
        mMainHandler = new Handler();
        if (null == context || null == attrs) {
            return;
        }

        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ClockView);
        mClockBgColor = typedArray.getColor(R.styleable.ClockView_clock_background_color,
                context.getResources().getColor(R.color.black));
        mBigScaleLineColor = typedArray.getColor(R.styleable.ClockView_big_scale_line_color,
                context.getResources().getColor(R.color.white));
        mSmallScaleLineColor = typedArray.getColor(R.styleable.ClockView_small_scale_line_color,
                context.getResources().getColor(R.color.gray));
        mHourHandColor = typedArray.getColor(R.styleable.ClockView_hour_hand_color,
                context.getResources().getColor(R.color.white));
        mMinuteHandColor = typedArray.getColor(R.styleable.ClockView_minute_hand_color,
                context.getResources().getColor(R.color.white));
        mSecondHandColor = typedArray.getColor(R.styleable.ClockView_second_hand_color,
                context.getResources().getColor(R.color.red));
        typedArray.recycle();
    }

    /**
     * 计算view的宽高,在onDraw()之前
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int measuredWidth = getMeasuredWidth();
        int measuredHeight = getMeasuredHeight();
        int mViewWidth = Math.min(measuredWidth, measuredHeight);
        //30为时钟到边界的距离
        mRadius = mViewWidth / 2 - 30;
        //除2计算出中心坐标
        mCenterX = mCenterY = mViewWidth >> 1;
        //设置宽高,将控件设置成正方形
        setMeasuredDimension(mViewWidth, mViewWidth);
    }

    @Override
    protected void onDraw(Canvas canvas) {//画图canvas为画布
        super.onDraw(canvas);
        Calendar calendar = Calendar.getInstance();
        //小时
        int hour = calendar.get(Calendar.HOUR);
        //分钟
        int minute = calendar.get(Calendar.MINUTE);
        //秒
        int second = calendar.get(Calendar.SECOND);
        //毫秒
        int milliSecond = calendar.get(Calendar.MILLISECOND);
        drawBackground(canvas);
        drawScaleLine(canvas);
        //画出时针
        drawHourHand(canvas, hour, minute);
        //画出分针
        drawMinuteHand(canvas, minute, second);
        //画出秒针
        drawSecondHand(canvas, second, milliSecond);
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                invalidate();
            }
        };
        mMainHandler.postDelayed(runnable, 50);
    }


    /**
     * 画背景
     */
    private void drawBackground(Canvas canvas) {
        mBackgroundPaint.setAntiAlias(true);
        mBackgroundPaint.setColor(mClockBgColor);
        canvas.drawCircle(mCenterX, mCenterY, mRadius, mBackgroundPaint);
    }

    /**
     * 画刻度线
     *
     * @param canvas
     */
    private void drawScaleLine(Canvas canvas) {
        //设置大刻度的颜色
        mScaleLinePaint.setColor(mBigScaleLineColor);
        //设置画笔的宽度,大刻度的刻度宽为5
        mScaleLinePaint.setStrokeWidth(5);
        //刻度线距离时钟边的距离为20
        int scaleLineMargin = 20;
        //大刻度线的长度
        int scaleLineLength = 60;
        //画12个大刻度
        for (int i = 0; i < 12; i++) {
            double radians = Math.toRadians(-90 + 30 * i);
            double cos = Math.cos(radians);
            double sin = Math.sin(radians);
            //使用三角函数计算末端的x值
            int stopX = (int) (cos * (mRadius - scaleLineMargin));
            //使用三角函数计算末端的y值
            int stopY = (int) (sin * (mRadius - scaleLineMargin));
            //使用三角函数计算初始端的x值
            int startX = (int) (cos * (mRadius - scaleLineMargin - scaleLineLength));
            //使用三角函数计算初始端的y值
            int startY = (int) (sin * (mRadius - scaleLineMargin - scaleLineLength));
            //画线
            canvas.drawLine(mCenterX + startX, mCenterY + startY,
                    mCenterX + stopX, mCenterY + stopY, mScaleLinePaint);
        }
        //设置小刻度颜色
        mScaleLinePaint.setColor(mSmallScaleLineColor);
        //设置画笔的宽度,小刻度的刻度宽为3
        mScaleLinePaint.setStrokeWidth(3);
        //小刻度线的长度为40
        scaleLineLength = 40;
        //画48个小刻度
        for (int i = 0; i < 60; i++) {
            if (i % 5 == 0) {
                continue;
            }
            double radians = Math.toRadians(-90 + 6 * i);
            double cos = Math.cos(radians);
            double sin = Math.sin(radians);
            //使用三角函数计算末端的x值
            int stopX = (int) (cos * (mRadius - scaleLineMargin));
            //使用三角函数计算末端的y值
            int stopY = (int) (sin * (mRadius - scaleLineMargin));
            //使用三角函数计算初始端的x值
            int startX = (int) (cos * (mRadius - scaleLineMargin - scaleLineLength));
            //使用三角函数计算初始端的y值
            int startY = (int) (sin * (mRadius - scaleLineMargin - scaleLineLength));
            //画线
            canvas.drawLine(mCenterX + startX, mCenterY + startY,
                    mCenterX + stopX, mCenterY + stopY, mScaleLinePaint);
        }
    }

    /**
     * 画出时针
     */
    private void drawHourHand(Canvas canvas, int hour, int minute) {
        int h = hour % 12;
        //时针颜色
        mHourPaint.setColor(mHourHandColor);
        // 时针长度,取半径的一般
        int hourLength = mRadius / 2;
        int hourWidth = 24;
        //时针宽度24
        mHourPaint.setStrokeWidth(hourWidth);
        double radians = Math.toRadians(-90 + 30 * h + minute * 0.5);
        //使用三角函数计算末端的x值
        int stopX = (int) (Math.cos(radians) * hourLength);
        //使用三角函数计算末端的y值
        int stopY = (int) (Math.sin(radians) * hourLength);

        //防锯齿
        mHourPaint.setAntiAlias(true);
        canvas.drawLine(mCenterX, mCenterY,
                mCenterX + stopX, mCenterY + stopY, mHourPaint);
        canvas.drawCircle(mCenterX, mCenterY, hourWidth >> 1, mHourPaint);
        canvas.drawCircle(stopX + mCenterX, mCenterY + stopY, hourWidth >> 1, mHourPaint);
        //时针空隙长度为70
        //使用三角函数计算初始端的x值
        int startX = (int) (Math.cos(radians) * (hourLength - 70));
        //使用三角函数计算初始端的y值
        int startY = (int) (Math.sin(radians) * (hourLength - 70));

        //时针中间的空隙
        mHourPaint.setStrokeWidth(hourWidth >> 1);
        mHourPaint.setColor(mClockBgColor);
        canvas.drawLine(mCenterX + startX, mCenterY + startY,
                mCenterX + stopX, mCenterY + stopY, mHourPaint);

        canvas.drawCircle(mCenterX + startX, mCenterY + startY, hourWidth >> 2, mHourPaint);
        canvas.drawCircle(mCenterX + stopX, mCenterY + stopY, hourWidth >> 2, mHourPaint);

    }

    /**
     * 画出分针
     */
    private void drawMinuteHand(Canvas canvas, int minute, int second) {
        //颜色问题
        mMinutePaint.setColor(mMinuteHandColor);
        //分针宽度
        int minuteHandWidth = 20;
        mMinutePaint.setStrokeWidth(minuteHandWidth);
        //分针长度为(半径 - 120)
        int minLenght = mRadius - 120;
        double radians = Math.toRadians(-90 + 6 * minute + second * 0.1);
        int stopX = (int) (Math.cos(radians) * minLenght);//使用三角函数计算末端的x值
        int stopY = (int) (Math.sin(radians) * minLenght);//使用三角函数计算末端的y值

        canvas.drawLine(mCenterX, mCenterY,
                mCenterX + stopX, mCenterY + stopY, mMinutePaint);//画线
        canvas.drawCircle(mCenterX, mCenterY, minuteHandWidth >> 1, mMinutePaint);
        canvas.drawCircle(stopX + mCenterX, mCenterY + stopY, minuteHandWidth >> 1, mMinutePaint);


        //分针中间的空隙,长度为 70
        int startX = (int) (Math.cos(radians) * (minLenght - 70));//使用三角函数计算初始端的x值
        int startY = (int) (Math.sin(radians) * (minLenght - 70));//使用三角函数计算初始端的y值

        mMinutePaint.setStrokeWidth(minuteHandWidth >> 1);
        mMinutePaint.setColor(mClockBgColor);
        canvas.drawLine(mCenterX + startX, mCenterY + startY,
                mCenterX + stopX, mCenterY + stopY, mMinutePaint);//画线
        canvas.drawCircle(mCenterX + startX, mCenterY + startY, minuteHandWidth >> 2, mMinutePaint);
        canvas.drawCircle(stopX + mCenterX, mCenterY + stopY, minuteHandWidth >> 2, mMinutePaint);

    }

    /**
     * 画出秒针
     */
    private void drawSecondHand(Canvas canvas, int second, int milliSecond) {
        mSecondPaint.setColor(mSecondHandColor);//设置画笔颜色
        mSecondPaint.setStrokeWidth(5);//设置画笔的宽度
        mSecondPaint.setAntiAlias(true);
        double ms = (6.0d * milliSecond) / 1000d;
        double argle = 6d * second + ms;
        //使用三角函数计算末端的x值,秒针长度为(半径-20)
        int stopX = (int) (Math.cos(Math.toRadians(-90 + argle)) * (mRadius - 20));
        //使用三角函数计算末端的y值
        int stopY = (int) (Math.sin(Math.toRadians(-90 + argle)) * (mRadius - 20));
        //使用三角函数计算初始端的x值
        int startX = (int) (Math.cos(Math.toRadians(-90 + argle - 180d)) * (50));
        //使用三角函数计算初始端的y值
        int startY = (int) (Math.sin(Math.toRadians(-90 + argle - 180d)) * (50));
        //画线
        canvas.drawLine(mCenterX + startX, mCenterY + startY,
                mCenterX + stopX, mCenterY + stopY, mSecondPaint);
        //画中间的圆
        canvas.drawCircle(mCenterX, mCenterY, 15, mSecondPaint);

        //画中间的白点
        mSecondPaint.setColor(mHourHandColor);//设置画笔颜色
        canvas.drawCircle(mCenterX, mCenterY, 5, mSecondPaint);
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        if (null == mMainHandler) {
            mMainHandler = new Handler();
        }
        invalidate();
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        if (null != mMainHandler) {
            mMainHandler.removeCallbacksAndMessages(null);
        }
    }
}

attr代码如下:

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <declare-styleable name="ClockView">
        <!-- 表盘颜色 -->
        <attr name="clock_background_color" format="color"/>
        <!-- 大刻度颜色 -->
        <attr name="big_scale_line_color" format="color"/>
        <!-- 小刻度颜色 -->
        <attr name="small_scale_line_color" format="color"/>
        <!-- 时针颜色 -->
        <attr name="hour_hand_color" format="color"/>
        <!-- 分针颜色 -->
        <attr name="minute_hand_color" format="color"/>
        <!-- 秒针颜色 -->
        <attr name="second_hand_color" format="color"/>
    </declare-styleable>

</resources>

Activity代码如下:

package com.ben.test;

import android.os.Bundle;

import androidx.appcompat.app.AppCompatActivity;


/**
 * 自定义控件时钟的demo
 */
public class ClockActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_custom);
    }
}

XML代码如下:

<?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"
    android:id="@+id/activity_custom"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <com.ben.test.ClockView
        android:id="@+id/cv_clock"
        android:layout_width="match_parent"
        app:clock_background_color="@color/black"
        android:layout_height="match_parent" />

</LinearLayout>

效果图
在这里插入图片描述
若遇有错的地方,还希望各位博友们多多指出

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值