Android自定义控件之时间百分比显示
江水绵延流转,日夜不息。于是子在川上曰:“逝者如斯夫,不舍昼夜”。时间如流水,人们总是在不知名的忙碌中让时间从指尖流走,时常盯着60进制的时分秒而无感,每每入夜之时才猛然惊觉,哀怨又彷徨。所以我萌生一个想法,想要将时间换成百分比进度条的形式。想从另一个角度看待时间,努力抓住时间的衣角,努力不让它从茫然中走失、从迷惘中逝去。
时间百分比控件继承自View,准备工作诸如Paint、TextPaint、Rect、初始化、构造函数等便不再细说,尾部将附上源码。核心要点便是如何将年、月、周、日、时、分、秒转化成百分比。我通过倒计时器CountDownTimer搭配SimpleDateFormat("yyyyMMddHHmmss").format(new Date(System.currentTimeMillis()),可以拿到当前时间的格式化的时间字符串。经过字符串截取,再解析转成整型就能获取到年、月、日、时、分、秒。接下来从最小的秒开始计算。针对秒,直接除以60。针对分钟,需要加上已过的秒的部分后再除以60。举个例子,30秒的时候,秒显示50%,此时分钟应该显示30/60/60=0.008333即0.8333%。时、日、年同理。
year = Integer.parseInt(strDateTime.substring(0, 4));
month = Integer.parseInt(strDateTime.substring(4, 6));
day = Integer.parseInt(strDateTime.substring(6, 8));
hour = Integer.parseInt(strDateTime.substring(8, 10));
min = Integer.parseInt(strDateTime.substring(10, 12));
second = Integer.parseInt(strDateTime.substring(12, 14));
timeInt[5] = second / 60f;
timeInt[4] = (min + timeInt[5]) / 60f;
timeInt[3] = (hour + timeInt[4]) / 24f;
timeInt[2] = (getIndexOfWeek() + timeInt[3]) / 7f;
timeInt[1] = (day - 1 + timeInt[3]) / (float) getDaysInMonth(year, month);
timeInt[0] = (month - 1 + timeInt[1]) / 12f;
针对周,默认周一为一周的第一天,代码中的getIndexOfWeek()通过以下方法获取:
/**
* 获取当前是一星期的第几天
* @return 所求
private int getIndexOfWeek(){
int [] weekDays = {6,0,1,2,3,4,5};
Calendar cal = Calendar.getInstance();
cal.setTime(new Date(System.currentTimeMillis()));
int w = cal.get(Calendar.DAY_OF_WEEK) - 1;
if (w < 0) {
w = 0;
return weekDays[w];
}
针对月,一三五七八十腊,三十一天永不差。闰年二月29天,平年二月28天。剩下的都是30天。代码中的getDaysInMonth(year, month)通过一下方法获取:
/**
* 返回某年某月的天数
* @param year 年
* @param month 月
* @return 所求
privates int getDaysInMonth(int year, int month){
int days;
int febDay = 28;
if(isLeap(year)){
febDay = 29;
switch (month){
case 2:
days = febDay;
break;
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
days = 31;
break;
case 4:
case 6:
case 9:
case 11:
days = 30;
break;
default:
days = 0;
return days;
* 是否是闰年
* @param year 年
* @return 所求
private boolean isLeap(int year){//能被100整除且能被400整除才是闰年,剩余的能被四整除且不能被100整除才是闰年。四年一闰,百年不闰,四百年再闰。 例如,2000年是闰年,1900年则是平年。
return year % 400 == 0 || year % 100 != 0 && year % 4 == 0;
}
经过上面的代码后已经得到六个浮点数,显示的时候乘以100再在后面加上百分号就行了。绘制一个百分比的代码如下,其他五个依葫芦画瓢即可:
str = "分钟已过" + timeInt[5] * 100 + "%";
textPaint.getTextBounds(str, 0, str.length(), rect);
paint.setColor(Color.LTGRAY);
canvas.drawRoundRect((float) MARGIN_LEFT, 5 * LINE_HEIGHT + rect.height(), MARGIN_LEFT + (getWidth() - 2 * MARGIN_LEFT) * timeInt[5], 6 * (float) LINE_HEIGHT + rect.height(), ROUND_CORNER, ROUND_CORNER, paint);
canvas.drawText(str, MARGIN_LEFT, 6 * LINE_HEIGHT - (rect.top + rect.bottom) / 2f, textPaint);
画进度条用的是画圆角矩形的方法。都是基本操作就不赘述了。最后贴出自定义控件全部源码。
package com.wenlin.myproduction.widget;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.CountDownTimer;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.view.View;
import androidx.annotation.Nullable;
import com.wenlin.myproduction.util.UIHelper;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
* @author 召唤希尔
* @Email 377979485@qq.com
* @desc 显示时间百分比,而不是60进制的分秒
* @time 2023-02-25 星期六 22:23
public class TimePercentView extends View {
private static final int LINE_HEIGHT = 120;
private static final int MARGIN_LEFT = 40;
private static final float ROUND_CORNER = 8;
private float[] timeInt = new float[6];
private Paint paint;
private TextPaint textPaint;
private Rect rect;
private SimpleDateFormat formatter;
private CountDownTimer timer;
private String strDateTime;
private Date date;
private int year;
private int month;
private int day;
private int hour;
private int min;
private int second;
private String str;
public TimePercentView(Context context) {
this(context, null);
public TimePercentView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
* 初始化
@SuppressLint("SimpleDateFormat")
private void init() {
paint = new Paint();
paint.setDither(true);
paint.setStyle(Paint.Style.FILL);
paint.setAntiAlias(true);
textPaint = new TextPaint();
textPaint.setColor(Color.BLACK);
textPaint.setTextSize(60);
rect = new Rect();
formatter = new SimpleDateFormat("yyyyMMddHHmmss");
timer = new CountDownTimer(Integer.MAX_VALUE, 1000) {
@Override
public void onTick(long millisUntilFinished) {
date = new Date(System.currentTimeMillis());
strDateTime = formatter.format(date);
date = null;
year = Integer.parseInt(strDateTime.substring(0, 4));
month = Integer.parseInt(strDateTime.substring(4, 6));
day = Integer.parseInt(strDateTime.substring(6, 8));
hour = Integer.parseInt(strDateTime.substring(8, 10));
min = Integer.parseInt(strDateTime.substring(10, 12));
second = Integer.parseInt(strDateTime.substring(12, 14));
timeInt[5] = second / 60f;
timeInt[4] = (min + timeInt[5]) / 60f;
timeInt[3] = (hour + timeInt[4]) / 24f;
timeInt[2] = (getTodayOfWeek() + timeInt[3]) / 7f;
timeInt[1] = (day - 1 + timeInt[3]) / (float) getDaysInMonth(year, month);
timeInt[0] = (month - 1 + timeInt[1]) / 12f;
invalidate();
@Override
public void onFinish() {
}.start();
* 获取当前是一星期的第几天
* @return 所求
private int getTodayOfWeek(){
int [] weekDays = {6,0,1,2,3,4,5};
Calendar cal = Calendar.getInstance();
cal.setTime(new Date(System.currentTimeMillis()));
int w = cal.get(Calendar.DAY_OF_WEEK) - 1;
if (w < 0) {
w = 0;
return weekDays[w];
* 返回某年某月的天数
* @param year 年
* @param month 月
* @return 所求
private int getDaysInMonth(int year, int month){
int days;
int febDay = 28;
if(isLeap(year)){
febDay = 29;
switch (month){
case 2:
days = febDay;
break;
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
days = 31;
break;
case 4:
case 6:
case 9:
case 11:
days = 30;
break;
default:
days = 0;
return days;
* 是否是闰年
* @param year 年
* @return 所求
private boolean isLeap(int year){//能被100整除且能被400整除才是闰年,剩余的能被四整除不能被100整除。四年一闰,百年不闰,四百年再闰。 例如,2000年是闰年,1900年则是平年。
return year % 400 == 0 || year % 100 != 0 && year % 4 == 0;
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
paint.setColor(Color.parseColor("#90ffffff"));
canvas.drawRoundRect(MARGIN_LEFT, 0, getWidth() - MARGIN_LEFT, 7 * (float) LINE_HEIGHT, ROUND_CORNER, ROUND_CORNER, paint);
str = "今年已过" + timeInt[0] * 100 + "%";
textPaint.getTextBounds(str, 0, str.length(), rect);
paint.setColor(Color.BLUE);
canvas.drawRoundRect((float) MARGIN_LEFT, rect.height(), MARGIN_LEFT + (getWidth() - 2 * MARGIN_LEFT) * timeInt[0], (float) LINE_HEIGHT + rect.height(), ROUND_CORNER, ROUND_CORNER, paint);
canvas.drawText(str, MARGIN_LEFT, LINE_HEIGHT - (rect.top + rect.bottom) / 2f, textPaint);
str = "本月已过" + timeInt[1] * 100 + "%";
textPaint.getTextBounds(str, 0, str.length(), rect);
paint.setColor(Color.RED);
canvas.drawRoundRect((float) MARGIN_LEFT, LINE_HEIGHT + rect.height(), MARGIN_LEFT + (getWidth() - 2 * MARGIN_LEFT) * timeInt[1], 2 * (float) LINE_HEIGHT + rect.height(), ROUND_CORNER, ROUND_CORNER, paint);
canvas.drawText(str, MARGIN_LEFT, 2 * LINE_HEIGHT - (rect.top + rect.bottom) / 2f, textPaint);
str = "本周已过" + timeInt[2] * 100 + "%";
textPaint.getTextBounds(str, 0, str.length(), rect);
paint.setColor(Color.GREEN);
canvas.drawRoundRect((float) MARGIN_LEFT, 2 * LINE_HEIGHT + rect.height(), MARGIN_LEFT + (getWidth() - 2 * MARGIN_LEFT) * timeInt[2], 3 * (float) LINE_HEIGHT + rect.height(), ROUND_CORNER, ROUND_CORNER, paint);
canvas.drawText(str, MARGIN_LEFT, 3 * LINE_HEIGHT - (rect.top + rect.bottom) / 2f, textPaint);
str = "今天已过" + timeInt[3] * 100 + "%";
textPaint.getTextBounds(str, 0, str.length(), rect);
paint.setColor(Color.YELLOW);
canvas.drawRoundRect((float) MARGIN_LEFT, 3 * LINE_HEIGHT + rect.height(), MARGIN_LEFT + (getWidth() - 2 * MARGIN_LEFT) * timeInt[3], 4 * (float) LINE_HEIGHT + rect.height(), ROUND_CORNER, ROUND_CORNER, paint);
canvas.drawText(str, MARGIN_LEFT, 4 * LINE_HEIGHT - (rect.top + rect.bottom) / 2f, textPaint);
str = "小时已过" + timeInt[4] * 100 + "%";
textPaint.getTextBounds(str, 0, str.length(), rect);
paint.setColor(Color.CYAN);
canvas.drawRoundRect((float) MARGIN_LEFT, 4 * LINE_HEIGHT + rect.height(), MARGIN_LEFT + (getWidth() - 2 * MARGIN_LEFT) * timeInt[4], 5 * (float) LINE_HEIGHT + rect.height(), ROUND_CORNER, ROUND_CORNER, paint);
canvas.drawText(str, MARGIN_LEFT, 5 * LINE_HEIGHT - (rect.top + rect.bottom) / 2f, textPaint);
str = "分钟已过" + timeInt[5] * 100 + "%";
textPaint.getTextBounds(str, 0, str.length(), rect);
paint.setColor(Color.LTGRAY);
canvas.drawRoundRect((float) MARGIN_LEFT, 5 * LINE_HEIGHT + rect.height(), MARGIN_LEFT + (getWidth() - 2 * MARGIN_LEFT) * timeInt[5], 6 * (float) LINE_HEIGHT + rect.height(), ROUND_CORNER, ROUND_CORNER, paint);
canvas.drawText(str, MARGIN_LEFT, 6 * LINE_HEIGHT - (rect.top + rect.bottom) / 2f, textPaint);
str = "时间:" + strDateTime;
textPaint.getTextBounds(str, 0, str.length(), rect);
canvas.drawText(str, MARGIN_LEFT, 8 * LINE_HEIGHT - (rect.top + rect.bottom) / 2f, textPaint);
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();