前言:實(shí)現(xiàn)完前篇文章中的熒光時(shí)鐘后拌屏,突然想起大學(xué)期間做數(shù)字電路實(shí)驗(yàn)經(jīng)常見到的LED數(shù)字顯示屏萍鲸,數(shù)字電路的課設(shè)也用 LED 數(shù)字結(jié)合簡(jiǎn)單的電路做了一個(gè)簡(jiǎn)單的老虎機(jī)游戲趟妥,甚是懷念钝侠。好吧脱柱!開始實(shí)現(xiàn)一個(gè) 簡(jiǎn)單的LED 數(shù)字時(shí)鐘伐弹!
LED 數(shù)字時(shí)鐘效果圖
image
1. 如何實(shí)現(xiàn)LED數(shù)字
LED 數(shù)字無非就是由七根線組成,只要根據(jù)數(shù)字0-9線條的組成特性榨为,畫出對(duì)應(yīng)的線條即可得到相應(yīng)數(shù)字惨好。
基本思路:畫完一個(gè)數(shù)字后,將畫布移動(dòng)一定的偏移量随闺,繼續(xù)畫下一個(gè)數(shù)字日川,依次類推。由于畫數(shù)字的動(dòng)作其實(shí)是重復(fù)的矩乐,我們可以封裝一個(gè)工具類NumPaintUtil來畫數(shù)字龄句。
每個(gè)LED數(shù)字自身的坐標(biāo)系示意圖參考如下,每根線的坐標(biāo)請(qǐng)根據(jù)代碼意會(huì)
image
public class NumPaintUtil {
private Canvas canvas;// view 的畫布
private float lineWidth;//線的長(zhǎng)度
private int lineColor;
private float padding=10;//豎直間距,默認(rèn)為10
/**
*
* @param canvas 畫布
* @param lineWidth 線長(zhǎng)
* @param lineColor 線的顏色
*/
public NumPaintUtil(Canvas canvas,float lineWidth,int lineColor){
this.canvas=canvas;
this.lineWidth=lineWidth;
this.lineColor=lineColor;
}
/**
*
* @param lineWidth 線長(zhǎng)
* @param lineColor 線的顏色
*/
public NumPaintUtil(float lineWidth,int lineColor){
this.lineWidth=lineWidth;
this.lineColor=lineColor;
}
public Canvas getCanvas() {
return canvas;
}
/**
*
* 調(diào)用drawNumber之前需設(shè)置畫布對(duì)象
* @param canvas
*/
public void setCanvas(Canvas canvas) {
this.canvas = canvas;
}
/**
*
* 根據(jù)0-9的特性繪制線條從而實(shí)現(xiàn)對(duì)應(yīng)的數(shù)字<BR/>
* 使用前,需初始化設(shè)置canvas,并且請(qǐng)將 canvas 移動(dòng)到合適的位置
* @param num 數(shù)字
*/
public void drawNumber(int num){
if(canvas==null){
try{
throw new CanvasNullPointException("canvas is null,please init canvas");
}catch (CanvasNullPointException e){
e.printStackTrace();
}
return;
}
switch (num) {
case 0:
/**
* 去掉中間線即可
* ——
* | |
* | |
* ——
*/
drawTopLeftLine();
drawTopLine();
drawBottomLine();
drawTopRightLine();
drawBottomLeftLine();
drawBottomRightLine();
break;
case 1:
/**
* 只畫右上和右下的線
*
* |
* |
*
*/
drawTopRightLine();
drawBottomRightLine();
break;
case 2:
/**
* 去掉左上和右下
*
* ——
* |
* ——
* |
* ——
*
*/
drawCenterLine();
drawTopLine();
drawBottomLine();
drawTopRightLine();
drawBottomLeftLine();
break;
case 3:
/**
* 去掉左上和左下
*
* ——
* |
* ——
* |
* ——
*
*/
drawCenterLine();
drawTopLine();
drawBottomLine();
drawTopRightLine();
drawBottomRightLine();
break;
case 4:
/**
* 去掉頂部散罕、底部和左下
*
*
* | |
* ——
* |
*
*/
drawCenterLine();
drawTopLeftLine();
drawTopRightLine();
drawBottomRightLine();
break;
case 5:
/**
* 去掉右上和左下
*
* ——
* |
* ——
* |
* ——
*
*/
drawCenterLine();
drawTopLeftLine();
drawTopLine();
drawBottomLine();
drawBottomRightLine();
break;
case 6:
/**
* 去掉右上
*
* ——
* |
* ——
* | |
* ——
*
*/
drawCenterLine();
drawTopLine();
drawBottomLine();
drawTopLeftLine();
drawBottomLeftLine();
drawBottomRightLine();
break;
case 7:
/**
* ——
* |
*
* |
*/
drawTopLine();
drawTopRightLine();
drawBottomRightLine();
break;
case 8:
/**
* 全保留
* __
* | |
* ——
* | |
* ——
*/
drawCenterLine();
drawTopLeftLine();
drawTopLine();
drawBottomLine();
drawTopRightLine();
drawBottomLeftLine();
drawBottomRightLine();
break;
case 9:
/**
* 去掉左下
* __
* | |
* ——
* |
* ——
*/
drawCenterLine();
drawTopLeftLine();
drawTopLine();
drawBottomLine();
drawTopRightLine();
drawBottomRightLine();
break;
}
}
public class CanvasNullPointException extends NullPointerException{
public CanvasNullPointException(String msg){
super(msg);
}
}
/**
* 畫中間線
*
*/
private void drawCenterLine() {
Paint numPaint = getPaint(lineColor);
canvas.drawLine(-lineWidth / 2, 0, lineWidth / 2, 0, numPaint);
}
/**
* 畫top 線
*
*/
private void drawTopLine() {
Paint numPaint = getPaint(lineColor);
canvas.drawLine(-lineWidth / 2, -lineWidth - padding, lineWidth / 2, -lineWidth - padding, numPaint);
}
/**
* 畫底部的線
*
*/
private void drawBottomLine() {
Paint numPaint = getPaint(lineColor);
canvas.drawLine(-lineWidth / 2, lineWidth + padding, lineWidth / 2, lineWidth + padding, numPaint);
}
/**
* 畫左上的線
*
*/
private void drawTopLeftLine() {
Paint numPaint = getPaint(lineColor);
canvas.drawLine(-lineWidth / 2, -padding/2, -lineWidth / 2, -padding/2 - lineWidth, numPaint);
}
/**
* 畫右上的線
*
*/
private void drawTopRightLine() {
Paint numPaint = getPaint(lineColor);
canvas.drawLine(lineWidth / 2, -padding/2, lineWidth / 2, -padding/2 - lineWidth, numPaint);
}
/**
* 畫左下
*
*/
private void drawBottomLeftLine() {
Paint numPaint = getPaint(lineColor);
canvas.drawLine(-lineWidth / 2, padding/2, -lineWidth / 2, padding/2 + lineWidth, numPaint);
}
/**
* 畫右下
*
*/
private void drawBottomRightLine() {
Paint numPaint = getPaint(lineColor);
canvas.drawLine(lineWidth / 2, padding/2, lineWidth / 2, padding/2 + lineWidth, numPaint);
}
/**
* 獲得對(duì)應(yīng)顏色的畫筆
*
* @param color
* @return
*/
public Paint getPaint(int color) {
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(color);
paint.setStrokeWidth(5f);
paint.setDither(true);
return paint;
}
}
2.使用 NumPaintUtil 來逐步繪制LED時(shí)鐘
2.1 第一步分歇,自定義NumClock繼承 View,實(shí)現(xiàn)以下構(gòu)造方法
public NumClock(Context context) {
super(context);
}
public NumClock(Context context, AttributeSet attrs) {
super(context, attrs);
obtainStyledAttrs(attrs);
}
2.2 第二步,添加必要屬性
//線的顏色
private int lineColor;
//中間兩小點(diǎn)的顏色
private int pointColor;
//是否展示秒數(shù)
private boolean showSeconds;
//控件真實(shí)長(zhǎng)寬
private int mRealWidth, mRealHeight;
private float centerX, centerY;
private float lineWidth;//線的長(zhǎng)度
private float padding;//數(shù)字間的間距
private float centerPadding;//時(shí)與分的間距
2.3 自定義 attr.xml 文件欧漱,增加以下屬性职抡,并獲取樣式
<declare-styleable name="NumClock">
<!-- 線條顏色 -->
<attr name="lineColor" format="color"></attr>
<!--是否顯示秒數(shù) -->
<attr name="showSecond" format="boolean"></attr>
<!-- 中間閃爍點(diǎn)的顏色-->
<attr name="pointColor" format="color"></attr>
</declare-styleable>
/**
* 獲取樣式,假如出現(xiàn)異常時(shí)取默認(rèn)值
*
* @param attrs
*/
private void obtainStyledAttrs(AttributeSet attrs) {
TypedArray array;
try {
array = getContext().obtainStyledAttributes(attrs, R.styleable.NumClock);
lineColor = array.getColor(R.styleable.NumClock_lineColor, Color.parseColor("#ffaacc"));
showSeconds = array.getBoolean(R.styleable.NumClock_showSecond, false);
pointColor = array.getColor(R.styleable.NumClock_pointColor, Color.parseColor("#ffaacc"));
} catch (Exception e) {
lineColor = Color.parseColor("#ffaacc");
pointColor = Color.parseColor("#ffaacc");
showSeconds = false;
}
}
2.4 測(cè)量 view 的真實(shí)長(zhǎng)寬,設(shè)置 view 的比例
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// 獲得該view真實(shí)的寬度和高度
mRealWidth = getMeasuredWidth() - getPaddingLeft() - getPaddingRight();
mRealHeight = getMeasuredHeight() - getPaddingTop() - getPaddingBottom();
//取最小值
int miniValue = Math.min(mRealHeight, mRealWidth);
//設(shè)置長(zhǎng)寬比為3:1
int height = miniValue;
int width = miniValue * 3;
//更改 view 的長(zhǎng)寬
setMeasuredDimension(width, height);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
//TODO 設(shè)置各個(gè)參數(shù)
centerX = w / 2;
centerY = h / 2;
mRealWidth = w;
mRealHeight = h;
//設(shè)置每一根線的長(zhǎng)度為 view 寬度的十分一
lineWidth = w / 10;
//數(shù)字間的間距
padding = (mRealWidth - 4 * lineWidth) / 8f;
//時(shí)與分之間的間距
centerPadding = 2 * padding;
//由于 onDraw 調(diào)用比較頻繁,故不在 onDraw 中實(shí)例化
numPaintUtil = new NumPaintUtil(lineWidth, lineColor);
}
2.5 開始繪制
PS:以下代碼中調(diào)用了多次 canvas的 translate 平移方法误甚,請(qǐng)先了解translate方法的機(jī)制及用途(這是自定義view 的基礎(chǔ)知識(shí))缚甩,本文不作闡述。
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//需在此設(shè)置numPaintUtil的 canvas 屬性
numPaintUtil.setCanvas(canvas);
//獲取當(dāng)前的時(shí)分秒
Calendar calendar = Calendar.getInstance();
int hour = calendar.get(Calendar.HOUR_OF_DAY);
int minute = calendar.get(Calendar.MINUTE);
//鎖定畫布
canvas.save();
//為了減少坐標(biāo)計(jì)算量,將坐標(biāo)原點(diǎn)從(0,0)移動(dòng)到 view 的中心點(diǎn)
canvas.translate(centerX, centerY);
//繪制時(shí)
drawHour(canvas, hour);
//是否閃爍點(diǎn)
if (isShow) {
drawPointBtHourNMinuter(canvas);
}
//更改標(biāo)志位
isShow = !isShow;
//繪制分
drawMinute(canvas, minute);
//是否顯示秒數(shù)
if (showSeconds) {
int second = calendar.get(Calendar.SECOND);
Paint textPaint = getPaint(lineColor);
textPaint.setTextSize(25f);
//繪制秒數(shù)
if (second < 10) {
canvas.drawText("0" + second, lineWidth / 2 + padding / 2, lineWidth, textPaint);
} else {
canvas.drawText(second + "", lineWidth / 2 + padding / 2, lineWidth, textPaint);
}
}
canvas.restore();
//每隔一秒刷新一次
postInvalidateDelayed(1000);
}
/**
* 繪制 時(shí)
*
* @param canvas 畫布
* @param hour 時(shí)
*/
public void drawHour(Canvas canvas, int hour) {
int tenOfHour = hour / 10;//十位
int oneOfHour = hour % 10;//個(gè)位
//計(jì)算可得第一個(gè)數(shù)字的中心點(diǎn) 與 此時(shí) canvas 的原點(diǎn)距離為 lineWidth+lineWidth/2 + padding + centerPadding / 2
float newCenterX = -(lineWidth+lineWidth/2 + padding + centerPadding / 2);
//將畫布往左平移 newCenterX 為負(fù)值
canvas.translate(newCenterX, 0);
//開始繪制「時(shí)」中的十位
numPaintUtil.drawNumber(tenOfHour);
//計(jì)算可得第二個(gè)數(shù)字中心點(diǎn)與第一個(gè)數(shù)字的中心點(diǎn)(即此時(shí) canvas 的原點(diǎn))距離為lineWidth + padding ,為正值
//所以將畫布在上一次偏移量的基礎(chǔ)上再往右平移 lineWidth + padding
canvas.translate(lineWidth + padding, 0);
//繪制「時(shí)」中的個(gè)位
numPaintUtil.drawNumber(oneOfHour);
}
/**
* 繪制時(shí)與分之間閃爍的兩個(gè)小點(diǎn)
*
* @param canvas
*/
public void drawPointBtHourNMinuter(Canvas canvas) {
Paint pointPaint = getPaint(pointColor);
//計(jì)算可得其坐標(biāo)值
canvas.drawCircle(lineWidth / 2 + centerPadding / 2, lineWidth / 2, 5, pointPaint);
canvas.drawCircle(lineWidth / 2 + centerPadding / 2, -lineWidth / 2, 5, pointPaint);
}
/**
* 繪制 分
*
* @param canvas 畫布
* @param minute 分鐘
*/
public void drawMinute(Canvas canvas, int minute) {
int tenOfMinute = minute / 10;//十位
int oneOfMinuter = minute % 10;//個(gè)位
//第三個(gè)數(shù)字的中心點(diǎn)與第二個(gè)數(shù)字的中心點(diǎn)(即此時(shí) canvas 的原點(diǎn))的距離 為lineWidth + centerPadding,為正值
//將畫布往右平移 lineWidth + centerPadding
canvas.translate(lineWidth + centerPadding, 0);
//繪制分鐘的十位
numPaintUtil.drawNumber(tenOfMinute);
//第四個(gè)數(shù)字的中心點(diǎn)與第三個(gè)數(shù)字的中心點(diǎn)(即此時(shí) canvas 的原點(diǎn))的距離為lineWidth + padding,為正值
//將畫布往右平移lineWidth + padding
canvas.translate(lineWidth + padding, 0);
//繪制分鐘的個(gè)位
numPaintUtil.drawNumber(oneOfMinuter);
}
/**
* 獲得對(duì)應(yīng)顏色的畫筆
*
* @param color 顏色
* @return
*/
public Paint getPaint(int color) {
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(color);
paint.setStrokeWidth(5f);
paint.setDither(true);
return paint;
}
源碼請(qǐng)瀏覽https://github.com/yuwenque/ClockSample