软件编程
位置:首页>> 软件编程>> Android编程>> Android实现简单时钟View的方法

Android实现简单时钟View的方法

作者:swt369  发布时间:2022-10-21 18:36:00 

标签:Android,时钟,View

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

Android实现简单时钟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&deg;。

//画刻度
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&deg;的倍数)还是小刻度。每次画完一条之后将坐标系顺时针旋转30&deg;,这样保证每次画的刻度线的坐标不变。

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

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

来源:http://blog.csdn.net/swt369/article/details/77429532

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com