全网整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:400-708-3566

Android实现简单时钟View的方法

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

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流程,产生指针运动的效果。

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


# Android  # 时钟  # View  # Android获取设备CPU核数、时钟频率以及内存大小的方法  # Android多功能时钟开发案例(实战篇)  # android实现widget时钟示例分享  # Android 仿日历翻页、仿htc时钟翻页、数字翻页切换效果  # Android多功能时钟开发案例(基础篇)  # android高仿小米时钟(使用Camera和Matrix实现3D效果)  # Android自定义动态壁纸开发(时钟)  # Android编程基于自定义控件实现时钟功能的方法  # Android仿小米时钟效果  # Android自定义View实现时钟功能  # 顺时针  # 完成后  # 移到  # 朝上  # 是在  # 后将  # 是一个非常  # 时用  # 大家多多  # mHeight  # mRadius  # mTickLengthSecond  # mWidth  # mPaintScaleShort  # mPaintOutline  # Canvas  # mPaintScaleLong  # private  # float  # ClockView 


相关文章: 公司网站制作费用多少,为公司建立一个网站需要哪些费用?  建站之星安装提示数据库无法连接如何解决?  linux top下的 minerd 木马清除方法  制作旅游网站html,怎样注册旅游网站?  如何处理“XML格式不正确”错误 常见XML well-formed问题解决方法  宝塔面板创建网站无法访问?如何快速排查修复?  利用JavaScript实现拖拽改变元素大小  C++用Dijkstra(迪杰斯特拉)算法求最短路径  开封网站制作公司,网络用语开封是什么意思?  网站制作网站,深圳做网站哪家比较好?  制作网站的基本流程,设计网站的软件是什么?  如何在IIS中新建站点并解决端口绑定冲突?  建站之星安装路径如何正确选择及配置?  Python多线程使用规范_线程安全解析【教程】  网站制作软件有哪些,制图软件有哪些?  如何快速搭建个人网站并优化SEO?  网站制作费用多少钱,一个网站的运营,需要哪些费用?  如何在新浪SAE免费搭建个人博客?  网站视频制作书签怎么做,ie浏览器怎么将网站固定在书签工具栏?  如何快速打造个性化非模板自助建站?  建站之星代理费用多少?最新价格详情介绍  学校为何禁止电信移动建设网站?  北京专业网站制作设计师招聘,北京白云观官方网站?  建站之星后台密码如何安全设置与找回?  网站建设制作、微信公众号,公明人民医院怎么在网上预约?  如何用免费手机建站系统零基础打造专业网站?  相亲简历制作网站推荐大全,新相亲大会主持人小萍萍资料?  成都品牌网站制作公司,成都营业执照年报网上怎么办理?  网站制作话术技巧,网站推广做的好怎么话术?  已有域名建站全流程解析:网站搭建步骤与建站工具选择  外贸公司网站制作哪家好,maersk船公司官网?  建站之星后台管理系统如何操作?  详解jQuery停止动画——stop()方法的使用  企业微网站怎么做,公司网站和公众号有什么区别?  视频网站制作教程,怎么样制作优酷网的小视频?  建站之星如何助力企业快速打造五合一网站?  如何挑选优质建站一级代理提升网站排名?  php条件判断怎么写_ifelse和switchcase的使用区别【对比】  深圳防火门网站制作公司,深圳中天明防火门怎么编码?  如何通过PHP快速构建高效问答网站功能?  如何通过VPS建站实现广告与增值服务盈利?  焦点电影公司作品,电影焦点结局是什么?  如何破解联通资金短缺导致的基站建设难题?  如何获取免费开源的自助建站系统源码?  如何通过虚拟主机快速完成网站搭建?  智能起名网站制作软件有哪些,制作logo的软件?  C++时间戳转换成日期时间的步骤和示例代码  长沙做网站要多少钱,长沙国安网络怎么样?  北京网站制作的公司有哪些,北京白云观官方网站?  如何通过二级域名建站提升品牌影响力? 

您的项目需求

*请认真填写需求信息,我们会在24小时内与您取得联系。