yi_master的博客

移动开发和区块链技术

Sample-如何自定义时钟,以及解决onDraw方法不调用的解决方案

效果如下,实现一个标准的时钟效果,实现效果如下
这里写图片描述
其实原理很简单,分别绘制时针,分针和秒针,并且在时针,分针和秒针的顶端绘制对应的时间,根据时间对画布进行旋转


代码如下
主Activity.java

public class CustomActivity extends Activity {

    private MyClockView mMyClockView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_custom_layout);
        mMyClockView = this.findViewById(R.id.clock_view);
    }
}

主页面

package com.hwj.custom.clock.view;

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

import java.util.Calendar;


public class MyClockView extends View {

    private int centerX;
    private int centerY;
    private int circleDadius;
    private Paint mCirlePaint;
    private Paint mTimePaint;
    private Handler tickHandler;

    public MyClockView(Context context){
        super(context);
        initClockView(context);
    }

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

    private void initClockView(Context context){

        //为了避免onDraw方法不调用,从而调用了setWillNotDraw();
//        setWillNotDraw(false);

        mCirlePaint = new Paint();
        mCirlePaint.setColor(Color.BLACK);
        mCirlePaint.setStyle(Paint.Style.STROKE);
        mCirlePaint.setAntiAlias(true);

        mTimePaint = new Paint();
        mTimePaint.setColor(Color.RED);
        mTimePaint.setStyle(Paint.Style.STROKE);
        mTimePaint.setAntiAlias(true);

        run();
    }

    public void run()
    {
        tickHandler = new Handler();
        tickHandler.post(tickRunnable);
    }

    private Runnable tickRunnable = new Runnable()
    {
        public void run()
        {
            postInvalidate();
            tickHandler.postDelayed(tickRunnable, 10);
        }
    };

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //获取圆心
        centerX = this.getMeasuredWidth() / 2;
        centerY = this.getMeasuredHeight() / 2;
        //设置圆的半径
        if(centerX > centerY){
            circleDadius = centerY;
        }else{
            circleDadius = centerX;
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
//        showInitClock(canvas);
        updateClockView(canvas);
    }

    /*
     * 首次展示时的页面,其实展示的就是时针,分针,秒针重合的一个view
     */
    private void showInitClock(Canvas canvas){
        canvas.drawCircle(centerX,centerY,circleDadius,mCirlePaint);
        //绘制时针
        mTimePaint.setStrokeWidth(5);
        canvas.drawLine(centerX,centerY,centerX,0 + 50,mTimePaint);
        canvas.save();
        canvas.restore();
        //绘制分针
        mTimePaint.setStrokeWidth(3);
        canvas.drawLine(centerX,centerY,centerX,0 + 20,mTimePaint);
        canvas.save();
        canvas.restore();
        //绘制秒针
        mTimePaint.setStrokeWidth(1);
        canvas.drawLine(centerX,centerY,centerX,0,mTimePaint);
        canvas.save();
        canvas.restore();
    }

    /*
     * 更新view区域,其原理就是旋转画布,重新绘制时针,分针和秒针
     */
    private void updateClockView(Canvas canvas){
        canvas.drawCircle(centerX,centerY,circleDadius,mCirlePaint);
        //获取当前时间
        Calendar cal = Calendar.getInstance();
        //Calendar.HOUR是12小时制
        int hour = cal.get(Calendar.HOUR);
        int minute = cal.get(Calendar.MINUTE);
        int second = cal.get(Calendar.SECOND);

        //一个时钟标记为12小时,一个圆是360度,共12段,顾一个小时的旋转角度为360 / 12 = 30
        //一个时钟标记为12小时,一个圆是360度,共60段,顾则每等分的角度为 360 / 60 = 6,即每分钟的旋转角度
        //一个时钟标记为12小时,一个圆是360度,共60段,即每秒旋转角度为 360 / 60 = 6
        float hourDegree = hour * (360 / 12) + minute * (360 / (60 * 12));
        float minDegree =  minute * (360 / (12 * 5)) + second * (360 / (60 * 60 * 12));
        float secDegree = second * (360 / (12 * 5));

        //顾我们可以总体计算出时针,分针,秒针的计算方法
        //时针转动角度 = 小时角度 + 分钟角度,分针和秒针 以此类推
        //需要说明的是,这里的分钟角度为什么不能使用minute * (360 / (12 * 5))来计算,
        //这是因为minute * (360 / (12 * 5))表示时钟总共被分针分割为60份,每份表示6度,不等于于现实里面每分钟的角度

        //绘制时针
        mTimePaint.setStrokeWidth(5);
        canvas.save();
        canvas.rotate(hourDegree, centerX, centerY);
        canvas.drawLine(centerX,centerY,centerX,0 + 50,mTimePaint);
        hour = (hour == 0) ? 12 : hour;
        canvas.drawText(String.valueOf(hour),centerX,0 + 50,mCirlePaint);
        canvas.restore();

        //绘制分针
        mTimePaint.setStrokeWidth(3);
        canvas.save();
        canvas.rotate(minDegree, centerX, centerY);
        canvas.drawLine(centerX,centerY,centerX,0 + 20,mTimePaint);
        canvas.drawText(String.valueOf(minute),centerX,0 + 20,mCirlePaint);
        canvas.restore();

        //绘制秒针
        mTimePaint.setStrokeWidth(1);
        canvas.save();
        canvas.rotate(secDegree, centerX, centerY);
        canvas.drawLine(centerX,centerY,centerX,0,mTimePaint);
        canvas.drawText(String.valueOf(second),centerX,0,mCirlePaint);
        canvas.restore();
    }
}

主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"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.hwj.custom.clock.view.CustomActivity">

    <com.hwj.custom.clock.view.MyClockView
        android:id="@+id/clock_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    </com.hwj.custom.clock.view.MyClockView>

</LinearLayout>

问题一:如果是继承自LinearLayout,不触发onDraw
解决方案1:调用setWillNotDraw(false)
解决方案2:继承View

阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yi_master/article/details/79962502
个人分类: Android自定义view
上一篇不在Application类里面如何对全部activity生命周期监听
下一篇自定义view 特效-环形View,数学在特效里面的运用
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭