自定义 View 实现钟表效果

一个很简单的自定义实例,直接上代码,注释已经写得很清楚了

attrs:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="MyClockView">
        <attr name="wb_radius" format="dimension"/>
        <!--背景颜色-->
        <attr name="wb_background_color" format="color"/>
        <!--0369点刻度颜色-->
        <attr name="wb_scale_large_long_color" format="color"/>
        <!--时刻刻度颜色-->
        <attr name="wb_scale_long_color" format="color"/>
        <!--非时刻刻度颜色-->
        <attr name="wb_scale_short_color" format="color"/>
        <!--时针颜色-->
        <attr name="wb_hour_pointer_color" format="color"/>
        <!--分针颜色-->
        <attr name="wb_minute_pointer_color" format="color"/>
        <!--秒针颜色-->
        <attr name="wb_second_pointer_color" format="color"/>
        <!--主题风格-->
        <attr name="wb_type" format="integer"/>
    </declare-styleable>
</resources>


MyClockView:

public class MyClockView extends View {

    private float mRadius; //外圆半径

    private int mBackground; //背景颜色
    private int mColorLong; //长线的颜色
    private int mColorShort; //短线的颜色
    private int mColorLargeLong; //0369点刻度颜色
    private int mHourPointColor; //时针的颜色
    private int mMinutePointColor; //分针的颜色
    private int mSecondPointColor; //秒针的颜色
    private int mType; //风格类型

    private Paint mPaint; //画笔
    private Calendar calendar;
    private float angleHour; //时针转过的角度
    private int angleMinute, angleSecond; //分针和秒针转过的角度
    private Bitmap background; //背景图片
    private Rect backgroundRect; // 用于缩放背景图片的矩形
    private float oneUnit; // 一个单位的长度,由半径得到

    private final static int NORMAL = 1; //普通风格
    private final static int FRESH = 2; //清新风格

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

    public MyClockView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initAttrs(context, attrs);
        initPaint();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//        取计算的长度和宽度的最小值,保证view所占空间为正方形
        int specSize = Math.min(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec));
        setMeasuredDimension(specSize, specSize);
        if (mRadius == - 1) //如果未设置半径,把半径设为view的长度的一半
            mRadius = specSize / 2;
        int intRadius = (int) mRadius;
        backgroundRect = new Rect(-intRadius, -intRadius, intRadius, intRadius);
        oneUnit = (float) (mRadius / 118.5);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        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);
        angleHour = ((hour + (minute + second * 1.0f / 60) * 1.0f / 60)) * 360 / 12; //时针转过的角度
        angleMinute = minute * 360 / 60; //分针转过的角度
        angleSecond = second * 360 / 60; //秒针转过的角度
        canvas.translate(getMeasuredWidth() / 2, getMeasuredHeight() / 2);
//        根据设置的风格进行绘制
        if (mType == NORMAL) {
            drawNormal(canvas);
        } else if (mType == FRESH) {
            drawFresh(canvas);
        }

//        每秒绘制一次
        postInvalidateDelayed(1000 - milliSecond);

    }

    //    初始化attr
    private void initAttrs(Context context, AttributeSet attrs) {
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.MyClockView);
        mBackground = ta.getColor(R.styleable.MyClockView_wb_background_color, Color.WHITE);
        mColorLong = ta.getColor(R.styleable.MyClockView_wb_scale_long_color, Color.BLACK);
        mColorLargeLong = ta.getColor(R.styleable.MyClockView_wb_scale_large_long_color, mColorLong);
        mColorShort = ta.getColor(R.styleable.MyClockView_wb_scale_short_color, Color.BLACK);
        mHourPointColor = ta.getColor(R.styleable.MyClockView_wb_hour_pointer_color, Color.BLACK);
        mMinutePointColor = ta.getColor(R.styleable.MyClockView_wb_minute_pointer_color, Color.BLACK);
        mSecondPointColor = ta.getColor(R.styleable.MyClockView_wb_second_pointer_color, Color.BLACK);
        mType = ta.getInt(R.styleable.MyClockView_wb_type, NORMAL);
        mRadius = ta.getDimension(R.styleable.MyClockView_wb_radius, - 1); //如果未设置半径,默认值为-1
        if (mType == NORMAL) {
            background = BitmapFactory.decodeResource(getResources(), R.drawable.clock);
        }
        ta.recycle();
    }

    //    初始化画笔
    private void initPaint() {
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
    }

    //    计算宽度
    private int measureWidth(int measureSpec) {
        int result = 0;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);
        if (specMode == MeasureSpec.EXACTLY) {
            result = specSize;
        } else {
            //若长度为wrap_content,如果未设置半径,把长度设为200,否则长度为半径的两倍
            if (specMode == MeasureSpec.AT_MOST) {
                if (mRadius == - 1) {
                    result = 200;
                } else {
                    result = (int) (mRadius * 2);
                }
            }
        }
        return result;
    }

    //    计算高度
    private int measureHeight(int measureSpec) {
        int result = 0;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);
        if (specMode == MeasureSpec.EXACTLY) {
            return specSize;
        } else {
            if (specMode == MeasureSpec.AT_MOST) {
                if (mRadius == - 1) {
                    result = 200;
                } else {
                    result = (int) (mRadius * 2);
                }
            }
        }
        return result;
    }


//    绘制普通风格
    private void drawNormal(Canvas canvas) {
        //绘制背景
        canvas.drawBitmap(background, null, backgroundRect, null);

//        绘制刻度
        canvas.save();
        mPaint.setColor(mColorLargeLong);
        mPaint.setStrokeWidth(oneUnit);
        mPaint.setStyle(Paint.Style.FILL);
        for (int i = 0; i <= 12; i++) {
            canvas.drawLine(0, -oneUnit * 78, 0, -oneUnit * 73, mPaint);
            canvas.rotate(30);
        }
        canvas.restore();

//        绘制时针
        canvas.save();
        float hourWidth = (float) (oneUnit * 1.6);
        mPaint.setColor(mHourPointColor);
        mPaint.setStrokeWidth(0);
        Path path = new Path();
        path.moveTo(-hourWidth, oneUnit * 15);
        path.lineTo(hourWidth, oneUnit * 15);
        path.lineTo(oneUnit, -oneUnit * 50);
        path.lineTo(-oneUnit, -oneUnit * 50);
        path.close();
        canvas.rotate(angleHour);
        canvas.drawPath(path, mPaint);
        canvas.restore();

//        绘制分针
        canvas.save();
        mPaint.setColor(mMinutePointColor);
        path.moveTo((float) (-oneUnit * 1.5), oneUnit * 15);
        path.lineTo((float) (oneUnit * 1.5), oneUnit * 15);
        path.lineTo((float) (oneUnit * 0.8), -oneUnit * 63);
        path.lineTo((float) (-oneUnit * 0.8), -oneUnit * 63);
        path.close();
        canvas.rotate(angleMinute);
        canvas.drawPath(path, mPaint);
        canvas.restore();

//        绘制秒针
        canvas.save();
        mPaint.setColor(mSecondPointColor);
        mPaint.setStrokeWidth((float) (oneUnit * 1.6));
        canvas.rotate(angleSecond);
        canvas.drawLine(0, -oneUnit * 72, 0, oneUnit * 15, mPaint);
        canvas.restore();

//        绘制中心点
        mPaint.setStrokeWidth(0);
        canvas.drawCircle(0, 0, oneUnit * 4, mPaint);

    }

//    绘制清新风格
    private void drawFresh(Canvas canvas) {
        canvas.save();
        mPaint.setColor(mBackground);
        mPaint.setStyle(Paint.Style.FILL);
        canvas.drawCircle(0, 0, mRadius, mPaint);
        canvas.restore();

        canvas.save();
        mPaint.setColor(mColorLargeLong);
        mPaint.setStrokeWidth(0);
        RectF largeLongRectF = new RectF(-oneUnit, -mRadius, oneUnit, (-mRadius + oneUnit * 20));
        for (int i = 0; i <= 4; i++) {
            canvas.drawRoundRect(largeLongRectF, oneUnit, oneUnit, mPaint);
            canvas.rotate(90);
        }

        mPaint.setColor(mColorLong);
        RectF longRectF = new RectF(-oneUnit, -mRadius, oneUnit, (-mRadius + oneUnit * 31));
        for (int i = 0; i <= 12; i++) {
            if (i % 3 != 0) {
                canvas.drawRoundRect(longRectF, oneUnit, oneUnit, mPaint);
            }
            canvas.rotate(30);
        }

        mPaint.setColor(mColorShort);
        RectF shortRectF = new RectF(-oneUnit, -mRadius, oneUnit, -mRadius + oneUnit * 6);
        for (int i = 0; i <= 60; i++) {
            if (i % 5 != 0) {
                canvas.drawRoundRect(shortRectF, oneUnit, oneUnit, mPaint);
            }
            canvas.rotate(6);
        }
        canvas.restore();


        canvas.save();
        float hourWidth = (float) (oneUnit * 3.5);
        RectF hourRectF = new RectF(-hourWidth, -oneUnit * 61, hourWidth, 0);
        mPaint.setColor(mHourPointColor);
        canvas.rotate(angleHour);
        canvas.drawRoundRect(hourRectF, hourWidth, hourWidth, mPaint);
        canvas.restore();

        canvas.save();
        RectF minRectF = new RectF(-hourWidth, -oneUnit * 78, hourWidth, 0);
        mPaint.setColor(mMinutePointColor);
        canvas.rotate(angleMinute);
        canvas.drawRoundRect(minRectF, hourWidth, hourWidth, mPaint);
        canvas.restore();

        canvas.save();
        float secondWidth = (float) (oneUnit * 1.5);
        RectF secondRectF = new RectF(-secondWidth, -mRadius, secondWidth, oneUnit * 20);
        mPaint.setColor(mSecondPointColor);
        canvas.rotate(angleSecond);
        canvas.drawRoundRect(secondRectF, secondWidth, secondWidth, mPaint);
        canvas.restore();

        mPaint.setColor(mHourPointColor);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth((float) (oneUnit * 2.5));
        canvas.drawCircle(0, 0, (float) (oneUnit * 5.25), mPaint);

        mPaint.setColor(mSecondPointColor);
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setStrokeWidth(0);
        canvas.drawCircle(0, 0, oneUnit * 4, mPaint);

    }
}


添加到 Activity:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:custom="http://schemas.android.com/apk/res-auto"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.ivy.module.app.MainActivity">


    <com.ivy.module.app.MyClockView
        android:layout_width="220dp"
        android:layout_height="220dp"
        android:layout_gravity="center_horizontal"
        custom:wb_hour_pointer_color="@android:color/black"
        custom:wb_minute_pointer_color="#A996FF"
        custom:wb_second_pointer_color="#FF0000"
        custom:wb_scale_large_long_color="#cec8d8"
        custom:wb_scale_long_color="#cec8d8"
        custom:wb_type="1"/>


    <com.ivy.module.app.MyClockView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        custom:wb_radius="120dp"
        custom:wb_hour_pointer_color="#413c5a"
        custom:wb_minute_pointer_color="#BCACEE"
        custom:wb_second_pointer_color="#FF3B7A"
        custom:wb_scale_large_long_color="#9888E0"
        custom:wb_scale_long_color="#D4CBF2"
        custom:wb_scale_short_color="#CBC5E9"
        custom:wb_type="2"/>

</LinearLayout>


效果图:



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值