唔得閑都要搞事之實(shí)現(xiàn)LED數(shù)字時(shí)鐘

前言:實(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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末窑邦,一起剝皮案震驚了整個(gè)濱河市擅威,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌冈钦,老刑警劉巖郊丛,帶你破解...
    沈念sama閱讀 217,509評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡宾袜,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門驾窟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來庆猫,“玉大人,你說我怎么就攤上這事绅络≡屡啵” “怎么了?”我有些...
    開封第一講書人閱讀 163,875評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵恩急,是天一觀的道長(zhǎng)杉畜。 經(jīng)常有香客問我,道長(zhǎng)衷恭,這世上最難降的妖魔是什么此叠? 我笑而不...
    開封第一講書人閱讀 58,441評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮随珠,結(jié)果婚禮上灭袁,老公的妹妹穿的比我還像新娘。我一直安慰自己窗看,他們只是感情好茸歧,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著显沈,像睡著了一般软瞎。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上拉讯,一...
    開封第一講書人閱讀 51,365評(píng)論 1 302
  • 那天涤浇,我揣著相機(jī)與錄音,去河邊找鬼遂唧。 笑死芙代,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的盖彭。 我是一名探鬼主播纹烹,決...
    沈念sama閱讀 40,190評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼召边!你這毒婦竟也來了铺呵?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,062評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤隧熙,失蹤者是張志新(化名)和其女友劉穎片挂,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,500評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡音念,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評(píng)論 3 335
  • 正文 我和宋清朗相戀三年沪饺,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片闷愤。...
    茶點(diǎn)故事閱讀 39,834評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡整葡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出讥脐,到底是詐尸還是另有隱情遭居,我是刑警寧澤,帶...
    沈念sama閱讀 35,559評(píng)論 5 345
  • 正文 年R本政府宣布旬渠,位于F島的核電站俱萍,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏告丢。R本人自食惡果不足惜枪蘑,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望芋齿。 院中可真熱鬧腥寇,春花似錦、人聲如沸觅捆。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)栅炒。三九已至掂摔,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間赢赊,已是汗流浹背乙漓。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留释移,地道東北人叭披。 一個(gè)月前我還...
    沈念sama閱讀 47,958評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像玩讳,于是被迫代替她去往敵國(guó)和親涩蜘。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,111評(píng)論 25 707
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫(kù)熏纯、插件同诫、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,102評(píng)論 4 62
  • 第二章,全息北京交通鏡像 “好的樟澜,先生误窖,我已接入所有數(shù)據(jù)接口及視頻”手機(jī)影子已經(jīng)打開了所有的鏡像系統(tǒng)接口叮盘,瞬間在北...
    眾心無相閱讀 227評(píng)論 1 1
  • 東吳山上空,晴空萬(wàn)里霹俺。 “小少姬柔吼!小少姬!你慢點(diǎn)丙唧,小的快跟不上了嚷堡!” “哪里來的這么多廢話。木里我要是因?yàn)槟惚坏?..
    huihui醬閱讀 349評(píng)論 0 4
  • 《路過艇棕,這個(gè)世界教我的事》五 “那些飄蕩的日子,那些泥濘的道路串塑,偶爾被淚水染湮……然而有些路該繼續(xù)走沼琉,有些相遇在未...
    Erina_li10閱讀 250評(píng)論 1 3