java自定义时间的时钟_自定义View_自定义时钟ClockView

本文介绍了一种自定义时钟View的方法,通过Android Canvas绘制时钟界面,包括时针、分针、秒针及刻度,并实现了动态更新时间的功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前段时间一直忙着学理财给自己充电,有一段时间没写代码了,前两天做了一个梦,梦见自己在写代码,是做了一个自定义时钟的一个东西,然后我醒来后就想着把这个效果实现以下,也算是“梦”想成真了。先来看下效果图吧~

2fe77ef5dd05

OK,话不多说,直接安排~

1.初始化画笔

定义好需要的画笔,这里我们先定义4个,分别是绘制背景、基本元素、指针、数字四个Paint画笔。然后初始化进行画笔的基本设置。

/**

* 背景绘制画笔

*/

private Paint mPaintBg;

/**

* 时钟元素画笔

*/

private Paint mPaint;

/**

* 绘制指针的画笔

*/

private Paint mPaintLine;

/**

* 绘制数字的画笔

*/

private Paint mPaintText;

//------------------------------------------------------------------------------

/**

* 初始化

*/

private void initView() {

mPaintBg = new Paint();

mPaintBg.setAntiAlias(true);

mPaintBg.setColor(Color.BLACK);

mPaintBg.setStrokeWidth(dip2px(mContext, 2));

mPaintBg.setStyle(Paint.Style.STROKE);

mPaint = new Paint();

mPaint.setAntiAlias(true);

mPaint.setColor(Color.RED);

mPaint.setStyle(Paint.Style.FILL);

mPaintLine = new Paint();

mPaintLine.setAntiAlias(true);

mPaintLine.setStyle(Paint.Style.FILL);

mPaintLine.setStrokeWidth(dip2px(mContext, 2));

mPaintText = new Paint();

mPaintText.setAntiAlias(true);

mPaintText.setColor(Color.BLACK);

mPaintText.setStyle(Paint.Style.STROKE);

mPaintText.setTextSize(30);

}

2.初始化变量

这里要定义三个变量来控制三个指针的长度,也用于后面计算坐标。

/**

* 指针长度-时针

*/

private float mDistanceHour;

/**

* 指针长度-分针

*/

private float mDistanceMinute;

/**

* 指针长度-秒针

*/

private float mDistanceSecond;

//------------------------------------------------------------------------------

@Override

protected void onSizeChanged(int w, int h, int oldw, int oldh) {

super.onSizeChanged(w, h, oldw, oldh);

mDistanceHour = w / 5 - dip2px(mContext, 7);

mDistanceMinute = mDistanceHour + dip2px(mContext, 18);

mDistanceSecond = mDistanceHour + dip2px(mContext, 45);

}

3.定义相关变量

这里我对时分秒分别定义了变量进行控制处理,主要是用来根据当前时间来计算指针所需要划过的角度。

/**

* 0-11

*/

private int mCurrentHour = 0;

/**

* 0-59

*/

private int mCurrentMinute = 0;

/**

* 0-59

*/

private int mCurrentSecond = 0;

OK,接下来上核心代码,也就是绘制部分。为了方便计算,我们把画笔移动到正中央,也就是先调用一下canvas.translate(getWidth() / 2, getHeight() / 2);然后再进行绘制。

4.绘制时钟基本元素

/**

* 绘制时钟基本的元素

*

* @param canvas

*/

private void drawClock(Canvas canvas) {

//绘制圆圈背景

canvas.drawCircle(0, 0, (getWidth() - dip2px(mContext, 2)) / 2, mPaintBg);

//绘制文字和小圆点

for (int i = 0; i < 12; i++) {

float r = getWidth() / 2 - offset;

float deg = i * 30 + 30;

float x = (float) (r * Math.sin(Math.PI * deg / 180));

float y = (float) (r * Math.cos(Math.PI * deg / 180));

canvas.drawCircle(x, -y, dip2px(mContext, 3), mPaint);

//绘制进度数字

String text = (i + 1) + "";

//获取文字宽度

float textWidth = mPaintText.measureText(text, 0, text.length());

float dx = x - x / 10 - textWidth / 2;

Paint.FontMetricsInt fontMetricsInt = mPaintText.getFontMetricsInt();

float dy = (fontMetricsInt.bottom - fontMetricsInt.top) / 2 - fontMetricsInt.bottom;

float baseLine = -(y - y / 10) + dy;

canvas.drawText(text, dx, baseLine, mPaintText);

}

}

到这里我们就能看到基本的样子已经出来了,如下图:

2fe77ef5dd05

5.绘制时针

/**

* 绘制时针

*

* @param canvas

*/

private void drawHour(Canvas canvas) {

mPaintLine.setColor(Color.BLACK);

/**

* 找到时间和弧度的关系,先计算出总的时间加在一起是多少个小时,

* 然后根据小时数计算出在时钟上需要绘制的角度是多少,再求出坐标进行绘制

*/

float hour = (float) mCurrentHour + (float) mCurrentMinute / 60 + (float) mCurrentSecond / 3600;

float deg1 = hour * 30;

Log.i(TAG, "度数deg1:" + hour);

float x1 = (float) (mDistanceHour * Math.sin(Math.PI * deg1 / 180));

float y1 = (float) (mDistanceHour * Math.cos(Math.PI * deg1 / 180));

//canvas.drawCircle(x1, -y1, 10, mPaintLine);

canvas.drawLine(0, 0, x1, -y1, mPaintLine);

}

6.绘制分针

/**

* 绘制分针

*

* @param canvas

*/

private void drawMinute(Canvas canvas) {

mPaintLine.setColor(Color.BLACK);

/**

* 找到时间和弧度的关系

*/

float minute = (float) mCurrentMinute + (float) mCurrentSecond / 60;

float deg1 = minute * 6;

Log.i(TAG, "===度数minute:" + minute + "===度数deg1:" + deg1);

float x1 = (float) (mDistanceMinute * Math.sin(Math.PI * deg1 / 180));

float y1 = (float) (mDistanceMinute * Math.cos(Math.PI * deg1 / 180));

//canvas.drawCircle(x1, -y1, 10, mPaintLine);

canvas.drawLine(0, 0, x1, -y1, mPaintLine);

}

7.绘制秒针

/**

* 绘制秒针

*

* @param canvas

*/

private void drawSecond(Canvas canvas) {

mPaintLine.setColor(Color.RED);

/**

* 找到时间和弧度的关系

*/

float deg1 = mCurrentSecond * 6;

Log.i(TAG, "===度数deg1:" + deg1);

float x1 = (float) (mDistanceSecond * Math.sin(Math.PI * deg1 / 180));

float y1 = (float) (mDistanceSecond * Math.cos(Math.PI * deg1 / 180));

//canvas.drawCircle(x1, -y1, 10, mPaintLine);

canvas.drawLine(0, 0, x1, -y1, mPaintLine);

}

8.动起来

如何动起来,就很简单了,我们只要每隔1秒进行绘制一次即可,这里我使用了Handler+Runnable的方式进行实现的,代码很简单就不单独列出来了,下面直接上完整代码。

ClockView.java

/**

* 自定义View系列-时钟Clock

*/

public class ClockView extends View {

private static final String TAG = ClockView.class.getSimpleName();

/**

* 上下文

*/

private Context mContext;

/**

* 背景绘制画笔

*/

private Paint mPaintBg;

/**

* 时钟元素画笔

*/

private Paint mPaint;

/**

* 绘制指针的画笔

*/

private Paint mPaintLine;

/**

* 绘制数字的画笔

*/

private Paint mPaintText;

/**

* 0-11

*/

private int mCurrentHour = 0;

/**

* 0-59

*/

private int mCurrentMinute = 0;

/**

* 0-59

*/

private int mCurrentSecond = 0;

/**

* 指针长度-时针

*/

private float mDistanceHour;

/**

* 指针长度-分针

*/

private float mDistanceMinute;

/**

* 指针长度-秒针

*/

private float mDistanceSecond;

/**

* 偏移量

*/

private float offset;

/**

* 时间间隔

*/

private int TIME = 1000;//默认每隔10ms重绘一次

/**

* Handler

*/

Handler handler = new Handler();

/**

* Runnable

*/

Runnable runnable = new Runnable() {

@Override

public void run() {

try {

handler.postDelayed(this, TIME);

switch (mTypeModel) {

case CURRENT_MODEL:

getCurrentTime();

break;

case DEFAULT_MODEL:

getDefaultTime();

break;

}

invalidate();

} catch (Exception e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

};

public ClockView(Context context) {

this(context, null);

}

public ClockView(Context context, @Nullable AttributeSet attrs) {

this(context, attrs, 0);

}

public ClockView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

mContext = context;

initView();

offset = dip2px(mContext, 10);

}

/**

* 初始化

*/

private void initView() {

mPaintBg = new Paint();

mPaintBg.setAntiAlias(true);

mPaintBg.setColor(Color.BLACK);

mPaintBg.setStrokeWidth(dip2px(mContext, 2));

mPaintBg.setStyle(Paint.Style.STROKE);

mPaint = new Paint();

mPaint.setAntiAlias(true);

mPaint.setColor(Color.RED);

mPaint.setStyle(Paint.Style.FILL);

mPaintLine = new Paint();

mPaintLine.setAntiAlias(true);

mPaintLine.setStyle(Paint.Style.FILL);

mPaintLine.setStrokeWidth(dip2px(mContext, 2));

mPaintText = new Paint();

mPaintText.setAntiAlias(true);

mPaintText.setColor(Color.BLACK);

mPaintText.setStyle(Paint.Style.STROKE);

mPaintText.setTextSize(30);

}

@Override

protected void onSizeChanged(int w, int h, int oldw, int oldh) {

super.onSizeChanged(w, h, oldw, oldh);

mDistanceHour = w / 5 - dip2px(mContext, 7);

mDistanceMinute = mDistanceHour + dip2px(mContext, 18);

mDistanceSecond = mDistanceHour + dip2px(mContext, 45);

}

@Override

protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

canvas.translate(getWidth() / 2, getHeight() / 2);

drawClock(canvas);

drawHour(canvas);

drawMinute(canvas);

drawSecond(canvas);

/**

* 绘制中心点

*/

canvas.drawCircle(0, 0, 20, mPaint);

}

/**

* 绘制时钟基本的元素

*

* @param canvas

*/

private void drawClock(Canvas canvas) {

//绘制圆圈背景

canvas.drawCircle(0, 0, (getWidth() - dip2px(mContext, 2)) / 2, mPaintBg);

//绘制文字和小圆点

for (int i = 0; i < 12; i++) {

float r = getWidth() / 2 - offset;

float deg = i * 30 + 30;

float x = (float) (r * Math.sin(Math.PI * deg / 180));

float y = (float) (r * Math.cos(Math.PI * deg / 180));

canvas.drawCircle(x, -y, dip2px(mContext, 3), mPaint);

//绘制进度数字

String text = (i + 1) + "";

//获取文字宽度

float textWidth = mPaintText.measureText(text, 0, text.length());

float dx = x - x / 10 - textWidth / 2;

Paint.FontMetricsInt fontMetricsInt = mPaintText.getFontMetricsInt();

float dy = (fontMetricsInt.bottom - fontMetricsInt.top) / 2 - fontMetricsInt.bottom;

float baseLine = -(y - y / 10) + dy;

canvas.drawText(text, dx, baseLine, mPaintText);

}

}

/**

* 绘制时针

*

* @param canvas

*/

private void drawHour(Canvas canvas) {

mPaintLine.setColor(Color.BLACK);

/**

* 找到时间和弧度的关系,先计算出总的时间加在一起是多少个小时,

* 然后根据小时数计算出在时钟上需要绘制的角度是多少,再求出坐标进行绘制

*/

float hour = (float) mCurrentHour + (float) mCurrentMinute / 60 + (float) mCurrentSecond / 3600;

float deg1 = hour * 30;

Log.i(TAG, "度数deg1:" + hour);

float x1 = (float) (mDistanceHour * Math.sin(Math.PI * deg1 / 180));

float y1 = (float) (mDistanceHour * Math.cos(Math.PI * deg1 / 180));

//canvas.drawCircle(x1, -y1, 10, mPaintLine);

canvas.drawLine(0, 0, x1, -y1, mPaintLine);

}

/**

* 绘制分针

*

* @param canvas

*/

private void drawMinute(Canvas canvas) {

mPaintLine.setColor(Color.BLACK);

/**

* 找到时间和弧度的关系

*/

float minute = (float) mCurrentMinute + (float) mCurrentSecond / 60;

float deg1 = minute * 6;

Log.i(TAG, "===度数minute:" + minute + "===度数deg1:" + deg1);

float x1 = (float) (mDistanceMinute * Math.sin(Math.PI * deg1 / 180));

float y1 = (float) (mDistanceMinute * Math.cos(Math.PI * deg1 / 180));

//canvas.drawCircle(x1, -y1, 10, mPaintLine);

canvas.drawLine(0, 0, x1, -y1, mPaintLine);

}

/**

* 绘制秒针

*

* @param canvas

*/

private void drawSecond(Canvas canvas) {

mPaintLine.setColor(Color.RED);

/**

* 找到时间和弧度的关系

*/

float deg1 = mCurrentSecond * 6;

Log.i(TAG, "===度数deg1:" + deg1);

float x1 = (float) (mDistanceSecond * Math.sin(Math.PI * deg1 / 180));

float y1 = (float) (mDistanceSecond * Math.cos(Math.PI * deg1 / 180));

//canvas.drawCircle(x1, -y1, 10, mPaintLine);

canvas.drawLine(0, 0, x1, -y1, mPaintLine);

}

/**

* 开始

*/

public void start() {

stop();

handler.postDelayed(runnable, TIME); //每隔TIMEms执行

}

public void stop() {

try {

handler.removeCallbacks(runnable);

} catch (Exception e) {

e.printStackTrace();

}

}

/**

* 获取当前时间

*/

private void getCurrentTime() {

Calendar now = Calendar.getInstance();

mCurrentHour = now.get(Calendar.HOUR_OF_DAY);

mCurrentMinute = now.get(Calendar.MINUTE);

mCurrentSecond = now.get(Calendar.SECOND);

}

private long timeSeconds = 32353450;

private void getDefaultTime() {

timeSeconds++;

mCurrentHour = (int) (timeSeconds / 60 / 60 % 60);

mCurrentMinute = (int) (timeSeconds / 60 % 60);

mCurrentSecond = (int) (timeSeconds % 60);

}

private TYPE_MODEL mTypeModel = TYPE_MODEL.DEFAULT_MODEL;

public enum TYPE_MODEL {

CURRENT_MODEL, DEFAULT_MODEL;

}

public void startSpeed() {

mTypeModel = TYPE_MODEL.DEFAULT_MODEL;

TIME = 1;

}

public void defaultModel() {

TIME = 1000;

mTypeModel = TYPE_MODEL.CURRENT_MODEL;

}

/**

* 根据手机的分辨率从 dp 的单位 转成为 px(像素)

*/

public static int dip2px(Context context, float dpValue) {

final float scale = context.getResources().getDisplayMetrics().density;

return (int) (dpValue * scale + 0.5f);

}

}

MainActivity.java

public class MainActivity extends AppCompatActivity {

private ClockView mClockView;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

mClockView = findViewById(R.id.view);

mClockView.start();

}

/**

* 加快版

*

* @param view

*/

public void clickSpeed(View view) {

mClockView.startSpeed();

}

/**

* 当前时间

*

* @param view

*/

public void clickDefault(View view) {

mClockView.defaultModel();

}

}

OK,结束,打完收工!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值