s时钟画布 android,Android实现简单时钟View的方法

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

3ca889507b7dbb6023c3cf02fa17471a.gif

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值