仿华为手机时钟

最近看到华为手机自带的时钟挺漂亮的,就想着自己做一个,先上效果图(不知道怎么传小图)


仿华为手机时钟_第1张图片
华为手机自带钟表.gif

仿华为手机时钟_第2张图片
自定义view实现.gif

自定义属性(其实可以有更多自定义属性):


    
        
        
        
        
        
        
        
        
    

自定义view:

public class HuaWeiClock extends View {
    /**
     * 背景颜色
     */
    private int backgroundColor;
    /**
     * 秒针竖线的颜色
     */
    private int secondLineColor;
    /**
     * 秒针红色点的颜色
     */
    private int secondPointColor;
    /**
     * 时间的颜色
     */
    private int timeColor;

    private Paint mPaint;

    /**
     * 背景宽度
     */
    private int widthBg;
    /**
     * 背景高度
     */
    private int heightBg;
    /**
     * 钟表半径
     */
    private int watchRadius;
    /**
     * 秒针红点的半径
     */
    private static final int SECOND_POINT_RADIUS = 20;
    /**
     * 线最长的长度
     */
    private static final int LINE_MAX_LENGTH = 60;
    /**
     * 线最短的长度
     */
    private static final int LINE_MIN_LENGTH = 30;
    /**
     * 秒刻度白线的数量
     */
    private static final int LINE_COUNT = 120;

    /**
     * 每根针占的角度
     */
    private static final int ONE_LINE_ANGLE = 360 / LINE_COUNT;

    /**
     * 秒针的角度
     */
    private float angle;

    private String time = "00:00";

    /**
     * 长于普通秒针刻度的驼峰一侧的条数
     */
    private static final int LONG_LINE_COUNT = 7;
    /**
     * 一侧7根长针的角度
     */
    private static final int LONG_LINES_ANGLE = ONE_LINE_ANGLE * LONG_LINE_COUNT;


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

    public HuaWeiClock(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public HuaWeiClock(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.HuaWeiClock);
        backgroundColor = typedArray.getColor(R.styleable.HuaWeiClock_backgroundColor, Color.parseColor("#003560"));
        secondLineColor = typedArray.getColor(R.styleable.HuaWeiClock_secondLineColor, Color.WHITE);
        secondPointColor = typedArray.getColor(R.styleable.HuaWeiClock_secondPointColor, Color.parseColor("#CE3228"));
        timeColor = typedArray.getColor(R.styleable.HuaWeiClock_timeColor, Color.WHITE);
        typedArray.recycle();
        initPaint();
        startTime();
    }


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

    /**
     * 获取时间,并通过RxJava实现动画
     */
    private void startTime() {
        //延时0秒后每隔100毫秒,刷新一次UI
        Observable.interval(0, 100, TimeUnit.MILLISECONDS)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer() {
                    @Override
                    public void accept(Long aLong) throws Exception {
                        Calendar calendar = Calendar.getInstance();
                        int second = calendar.get(Calendar.SECOND);
                        int milliSecond = calendar.get(Calendar.MILLISECOND);
                        angle = (float) (second * 1000 + milliSecond) * 6 / 1000f;
                        SimpleDateFormat minuteFormat = new SimpleDateFormat("HH:mm");
                        time = minuteFormat.format(calendar.getTime());
                        postInvalidate();
                    }
                }, new Consumer() {
                    @Override
                    public void accept(Throwable throwable) throws Exception {
                        Logger.d(throwable.getMessage());
                    }
                });
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int width = 0;
        int height = 0;
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        switch (widthMode) {
            case MeasureSpec.AT_MOST:
                width = widthSize * 3 / 4;
                break;
            case MeasureSpec.EXACTLY:
                width = widthSize;
                break;
            case MeasureSpec.UNSPECIFIED:
                break;
            default:
                break;
        }
        switch (heightMode) {
            case MeasureSpec.AT_MOST:
                height = heightSize / 2;
                break;
            case MeasureSpec.EXACTLY:
                height = heightSize;
                break;
            case MeasureSpec.UNSPECIFIED:
                break;
            default:
                break;
        }
        widthBg = width;
        heightBg = height;
        watchRadius = height * 2 / 5;
        setMeasuredDimension(width, height);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        drawBg(canvas);
        drawTickMark(canvas);
        drawSecondPoint(canvas);
        drawTime(canvas);
    }

    /**
     * 画背景
     *
     * @param canvas 画板
     */
    private void drawBg(Canvas canvas) {
        mPaint.setColor(backgroundColor);
        mPaint.setStyle(Paint.Style.FILL);
        RectF rectBg = new RectF(0, 0, widthBg, heightBg);
        canvas.drawRect(rectBg, mPaint);
    }

    /**
     * 画刻度线
     *
     * @param canvas 画板
     */
    private void drawTickMark(Canvas canvas) {
        mPaint.setColor(secondLineColor);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(3);
        for (int i = 0; i < LINE_COUNT; i++) {
            //角度差的绝对值
            float absoluteValue = Math.abs(i * ONE_LINE_ANGLE - angle);
            //求  刻度针线 和 秒针 之间的角度(小于180度)
            float differenceAngle = absoluteValue <= 180 ? absoluteValue : 360 - absoluteValue;
            //大于七根长线刻度的线,那么长度固定
            if (differenceAngle > LONG_LINES_ANGLE) {
                canvas.drawLine(widthBg / 2, heightBg / 2 - watchRadius, widthBg / 2, heightBg / 2 - watchRadius + LINE_MIN_LENGTH, mPaint);
                canvas.rotate(3, widthBg / 2, heightBg / 2);
            } else {
                canvas.drawLine(widthBg / 2, heightBg / 2 - watchRadius - (1 - differenceAngle / LONG_LINES_ANGLE) * (LINE_MAX_LENGTH - LINE_MIN_LENGTH), widthBg / 2, heightBg / 2 - watchRadius + LINE_MIN_LENGTH, mPaint);
                canvas.rotate(3, widthBg / 2, heightBg / 2);
            }
        }
    }

    /**
     * 画秒表的红点
     *
     * @param canvas 画布
     */
    private void drawSecondPoint(Canvas canvas) {
        mPaint.setColor(secondPointColor);
        mPaint.setStyle(Paint.Style.FILL);
        int secondPointRadiusBig = watchRadius - LINE_MIN_LENGTH - SECOND_POINT_RADIUS - 20;
        double pointAngle = angle * Math.PI / 180;
        canvas.drawCircle((float) (widthBg / 2 + secondPointRadiusBig * Math.sin(pointAngle)), (float) (heightBg / 2 - secondPointRadiusBig * Math.cos(pointAngle)), SECOND_POINT_RADIUS, mPaint);
    }

    /**
     * 画时间
     *
     * @param canvas 画布
     */
    private void drawTime(Canvas canvas) {
        mPaint.setColor(timeColor);
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setTextSize(widthBg / 7);
        Rect bounds = new Rect();
        mPaint.getTextBounds(time, 0, time.length(), bounds);
        Paint.FontMetricsInt fontMetrics = mPaint.getFontMetricsInt();
        int baseline = (getMeasuredHeight() - fontMetrics.bottom + fontMetrics.top) / 2 - fontMetrics.top;
        canvas.drawText(time, getMeasuredWidth() / 2 - bounds.width() / 2, baseline, mPaint);
    }
}

最后在布局文件中引入:

 

收工~~~

你可能感兴趣的:(仿华为手机时钟)