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

15人阅读 评论(0) 收藏 举报
分类:

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


代码如下
主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

查看评论

前端开发在线峰会

-
  • 1970年01月01日 08:00

自定义view的onDraw()方法不被调用

今天继承ImageView写了一个自定义的view,用canvas但是却不能在界面中
  • feiniao8651
  • feiniao8651
  • 2014-09-22 22:16:51
  • 1634

android 自定义view 不执行 ondraw的解决办法

public class BackgroundLayout extends LinearLayout { public BackgroundLayout(Contex...
  • ID19870510
  • ID19870510
  • 2011-09-04 03:21:18
  • 8395

android 自定义控件onDraw方法未被调用

今天先只在这记录一下 onDraw方法未被调用的解决办法,和大概原因,回头再仔细研究原因:我写了一个自定义控件通过debug打断点发现onDraw方法一直没有被调用,于是到网上查了一下,结果需要在自定...
  • gaoqingliang521
  • gaoqingliang521
  • 2017-06-26 10:28:31
  • 761

自定义View onDraw方法不被执行

一.引言: 想必大家以前也遇到過這個問題:出於項目的需要,我們有時需要 新建一個直接或者間接繼承View的類,以便複寫View提供的onDraw()方法,但有時我們反而得不到我們想要的結果,今天就說...
  • vbLittleBoy
  • vbLittleBoy
  • 2014-10-23 10:37:05
  • 1766

自定义viewGroup 为什么不走 onDraw方法?

自定义viewGroup的时候你一定会迫不及待的暴躁如我的去在onDraw方法中绘制,但是你会发现,onDraw方法根本就不会被调用(简直是日了哈士奇了)。其实看下viewGroup中的源码,上面就已...
  • sinat_26710701
  • sinat_26710701
  • 2017-05-04 16:40:24
  • 381

View的onDraw函数不被调用 .

参考: http://blog.sina.com.cn/s/blog_4b50130d0100u0uk.html http://blog.csdn.net/hearrt/article/detai...
  • neiloid
  • neiloid
  • 2012-10-04 12:29:20
  • 8998

关于自定义View初始化时不执行onDraw方法的笔记

如果自定义View,而不是自定义容器时,请检查自定义View的宽高是否出现0的情况。 如果自定义容器,请移步ViewGroup为什么不会调用onDraw。 当我直接继承View实现自定义V...
  • Drink_Spring
  • Drink_Spring
  • 2015-07-07 14:34:09
  • 1737

自定义控件invalidate()方法未成功调用onDraw()

写过自定义控件的大家都知道invalidate方法是Android请求重绘的方法。所以会调用到我们自己重写的onDraw方法。 但是在我最近写的一个控件时却没有调用他的onDraw方法。我所重写的控...
  • qq_28497681
  • qq_28497681
  • 2015-12-15 13:25:36
  • 2773

自定义view ondraw不执行的问题

onDraw函数不是在 invalidate 或者 posinvalidate调用后一定会执行!系统感觉你太快了Ondraw会调用偶尔几次,不会每次都调用ondraw! 后来,在处理任务里强...
  • mfc2003
  • mfc2003
  • 2015-01-23 17:26:26
  • 1309
    个人资料
    等级:
    访问量: 7046
    积分: 447
    排名: 11万+
    最新评论