当前位置: 移动技术网 > IT编程>移动开发>Android > Android实现简单时钟View的方法

Android实现简单时钟View的方法

2019年07月24日  | 移动技术网IT编程  | 我要评论

监狱培欲,智能手机加盟,秦琼传

通过canvas的平移与旋转简化绘图逻辑是一个非常有用的技巧,下面的时钟view就是利用这个方法完成的,省去了使用三角函数计算坐标的麻烦。

clock

package com.example.swt369.simpleclock;

import android.content.context;
import android.graphics.canvas;
import android.graphics.paint;
import android.support.annotation.nullable;
import android.util.attributeset;
import android.view.view;
import android.view.viewtreeobserver;
import android.widget.toast;

import java.util.calendar;

/**
 * created by swt369 on 2017/8/20.
 */

public class clockview extends view {
  //时钟各个部件的长度
  private float mscalelengthlong;
  private float mscalelengthshort;
  private float mticklengthhour;
  private float mticklengthminute;
  private float mticklengthsecond;
  //view的宽和高
  private float mwidth;
  private float mheight;
  //时钟半径
  private float mradius;

  //绘制各部件时用的paint
  private paint mpaintscalelong;
  private paint mpaintscaleshort;
  private paint mpaintoutline;
  private paint mpaintnum;
  private paint mpainttickhour;
  private paint mpainttickminute;
  private paint mpaintticksecond;

  private viewtreeobserver.onpredrawlistener onpredrawlistener;
  public clockview(final context context, @nullable attributeset attrs) {
    super(context, attrs);

    onpredrawlistener = new viewtreeobserver.onpredrawlistener() {
      //获取view宽高并计算各个部件的长度
      @override
      public boolean onpredraw() {
        mwidth = getmeasuredwidth();
        mheight = getmeasuredheight();
        mradius = math.min(mwidth,mheight) / 2 * 0.95f;
        mscalelengthlong = mradius * 0.1f;
        mscalelengthshort = mradius * 0.05f;
        mticklengthhour = mradius * 0.3f;
        mticklengthminute = mradius * 0.45f;
        mticklengthsecond = mradius * 0.6f;
        return true;
      }
    };
    getviewtreeobserver().addonpredrawlistener(onpredrawlistener);

    //点击显示具体时间
    setonclicklistener(new onclicklistener() {
      @override
      public void onclick(view v) {
        calendar calendar = calendar.getinstance();
        string time = string.format("当前时间:%02d:%02d:%02d",
            calendar.get(calendar.hour_of_day),calendar.get(calendar.minute),calendar.get(calendar.second));
        toast.maketext(context,time, toast.length_short).show();
      }
    });

    //初始化所有paint对象
    initializepaints();
  }

  @override
  protected void ondraw(canvas canvas) {
    if(mwidth == 0 || mheight == 0){
      return;
    }
    if(onpredrawlistener != null){
      getviewtreeobserver().removeonpredrawlistener(onpredrawlistener);
      onpredrawlistener = null;
    }
    //绘制时钟
    drawclock(canvas);
    //一秒后重绘
    postinvalidatedelayed(1000);
  }

  private void drawclock(canvas canvas) {
    //保存原始状态
    canvas.save();

    //将坐标系原点移到中心,并逆时针旋转90度。完成后x轴朝上。
    canvas.translate(mwidth / 2,mheight / 2);
    canvas.rotate(-90);

    //画外围轮廓
    canvas.drawcircle(0,0,mradius, mpaintoutline);

    //画刻度
    for(int i = 0 ; i < 12 ; i++){
      string num = string.valueof(i == 0 ? 12 : i);
      if(i % 3 == 0){
        canvas.drawline(mradius,0,mradius - mscalelengthlong,0, mpaintscalelong);
      }else {
        canvas.drawline(mradius,0,mradius - mscalelengthshort,0, mpaintscaleshort);
      }
      canvas.drawtext(num,mradius - mscalelengthlong - mpaintnum.measuretext(num) * 2,0, mpaintnum);

      //顺时针旋转30度
      canvas.rotate(30);
    }

    calendar calendar = calendar.getinstance();

    //画时针
    int hour = calendar.get(calendar.hour);
    canvas.save();
    canvas.rotate(hour * 30);
    canvas.drawline(0,0,mticklengthhour,0,mpainttickhour);
    canvas.restore();

    //画分针
    int minute = calendar.get(calendar.minute);
    canvas.save();
    canvas.rotate(minute * 6);
    canvas.drawline(0,0,mticklengthminute,0,mpainttickminute);
    canvas.restore();

    //画秒针
    int second = calendar.get(calendar.second);
    canvas.save();
    canvas.rotate(second * 6);
    canvas.drawline(0,0,mticklengthsecond,0,mpaintticksecond);
    canvas.restore();

    //恢复原始状态
    canvas.restore();
  }

  private void initializepaints(){
    mpaintscalelong = new paint();
    mpaintscalelong.setantialias(true);
    mpaintscalelong.setstrokewidth(5);

    mpaintscaleshort = new paint();
    mpaintscaleshort.setantialias(true);
    mpaintscaleshort.setstrokewidth(3);

    mpaintoutline = new paint();
    mpaintoutline.setstyle(paint.style.stroke);
    mpaintoutline.setantialias(true);
    mpaintoutline.setstrokewidth(5);

    mpaintnum = new paint();
    mpaintnum.settextsize(30);

    mpainttickhour = new paint();
    mpainttickhour.setantialias(true);
    mpainttickhour.setstrokewidth(6);

    mpainttickminute = new paint();
    mpainttickminute.setantialias(true);
    mpainttickminute.setstrokewidth(4);

    mpaintticksecond = new paint();
    mpaintticksecond.setantialias(true);
    mpaintticksecond.setstrokewidth(2);
  }
}

代码注释已经比较详细了,下面把比较重要的部分再说明一下:

//保存原始状态
canvas.save();

//省略中间部分...

//恢复原始状态
canvas.restore();

在绘图开始时调用canvas.save(),可以保存下未经任何平移、旋转操作的原始画布状态。在所有绘图工作完成后调用canvas.restore(),可以恢复到上一次保存的状态(类似进出栈的感觉)。

//将坐标系原点移到中心,并逆时针旋转90度。完成后x轴朝上。
canvas.translate(mwidth / 2,mheight / 2);
canvas.rotate(-90);

画布的平移与旋转可能比较抽象,可以想象成坐标系的平移与旋转。调用canvas.translate(dx,dy)相当于将坐标原点向x,y方向移动了dx,dy的距离,调用canvas.rotate(degree)相当于坐标系顺时针旋转了degree°。

//画刻度
for(int i = 0 ; i < 12 ; i++){
  string num = string.valueof(i == 0 ? 12 : i);
  if(i % 3 == 0){
    canvas.drawline(mradius,0,mradius - mscalelengthlong,0, mpaintscalelong);
  }else {
    canvas.drawline(mradius,0,mradius - mscalelengthshort,0, mpaintscaleshort);
  }
  canvas.drawtext(num,mradius - mscalelengthlong - mpaintnum.measuretext(num) * 2,0, mpaintnum);

  //顺时针旋转30度
  canvas.rotate(30);
}

根据i值决定是画大刻度(90°的倍数)还是小刻度。每次画完一条之后将坐标系顺时针旋转30°,这样保证每次画的刻度线的坐标不变。

//一秒后重绘
postinvalidatedelayed(1000);

作用是在1000ms(1s)后再次执行view的draw流程,产生指针运动的效果。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持移动技术网。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网