自定義LED點陣屏View

概述

看過演唱會的同學應該都看到過粉絲舉著LED點陣屏幕的牌子來支持自己心目中的男神或者女神侨把,感覺這種點陣屏幕的效果挺有意思的,于是花了點時間用Android實現了一下捂寿,實現效果如下:

實現效果

相關的概念

  1. 點陣字庫與矢量字庫
    點陣字庫就是每一個漢字用矩形點陣來表示龙优,然后用每個點的虛實來表示漢字的輪廓抬伺,常用來作為顯示字庫使用,這類點陣字庫漢字最大的缺點是不能放大读慎,一旦放大后就會發(fā)現文字邊緣的鋸齒教翩,常用的點陣矩陣有HZK12、HZK16和HZK24贪壳,我下面例子中的用到的字庫是HZK16饱亿。
    矢量字庫保存的是對每一個漢字的描述信息,比如一個筆劃的起始闰靴、終止坐標彪笼,半徑、弧度等等蚂且。在顯示配猫、打印這一類字庫時,要經過一系列的數學運算才能輸出結果杏死,但是這一類字庫保存的漢字理論上可以被無限地放大泵肄,筆劃輪廓仍然能保持圓滑捆交,打印時使用的字庫均為此類字庫.

  2. 點陣字庫結構
    在漢字的點陣字庫中,每個字節(jié)的每個位都代表一個漢字的一個點腐巢,每個漢字都是由一個矩形點陣組成品追,0代表沒有,1代表有點冯丙,將0和1分別用不同顏色畫出肉瓦,就形成了一個漢字。字庫根據字節(jié)所表示的點是一行還是一列將字庫的存儲方式分為橫向和縱向胃惜,目前多數的字庫都是橫向的存儲方式(用得最多的應該是早期UCDOS字庫)泞莉,縱向一般是因為有某些液晶是采用縱向掃描顯示法,為了提高顯示速度船殉,于是便把字庫矩陣做成縱向鲫趁,省得在顯示時還要做矩陣轉換。我們接下去所描述的HZK16就是一種縱向字庫利虫。對于16*16字庫來說饮寞,它所需要的位數共是16*16=256個位,每個字節(jié)為8位列吼,因此幽崩,每個漢字都需要用256/8=32個字節(jié)來表示。即每兩個字節(jié)代表一行的16個點寞钥,共需要16行慌申,顯示漢字時,只需一次性讀取32個字節(jié)理郑,并將每兩個字節(jié)為一行打印出來蹄溉,即可形成一個漢字.

  3. 漢字的區(qū)位碼
    漢字通過GB2312編碼即每個漢字用兩個byte來表示,第一個byte表示這個漢字在字庫文件中的區(qū)碼您炉,第二個byte表示這個漢字在字庫文件中的位碼柒爵,通過這兩個值可以計算到這個漢字在字庫文件中的相對位置,根據這個位置讀取接下來的32個byte(對于16*16字庫)赚爵,就對應著這個漢字對應的字模信息棉胀,字模信息其實就是一個byte數組。
    HZK16字庫是符合GB2312標準的16×16點陣字庫冀膝,HZK16的GB2312-80支持的漢字有6763個唁奢,符號682個。其中一級漢字有3755個窝剖,按聲序排列麻掸,二級漢字有3008個,按偏旁部首排列赐纱。

  4. 通過機內碼獲取文字對應字模信息的起始位置
    在PC機的文本文件中脊奋,漢字是以機內碼的形式存儲的熬北,每個漢字占用兩個字節(jié):第一個字節(jié)為區(qū)碼,為了與ASCII碼區(qū)別诚隙,范圍從十六進制的0A1H開始(小于80H的為ASCII碼字符)讶隐,對應區(qū)位碼中區(qū)碼的第一區(qū);第二個字節(jié)為位碼最楷,范圍也是從0A1H開始,對應某區(qū)中的第一個位碼待错。這樣籽孙,將漢字機內碼減去0A0A0H就得該漢字的區(qū)位碼。
    例如漢字“房”的機內碼為十六進制的“B7BF”火俄,其中“B7”表示區(qū)碼犯建,“BF”表示位碼。所以“房”的區(qū)位碼為0B7BFH-0A0A0H=171FH瓜客。將區(qū)碼和位碼分別轉換為十進制得漢字“房”的區(qū)位碼為“2331”适瓦,即“房”的字模信息位于第23區(qū)的第31個字的位置,由于一個區(qū)包含94個漢字谱仪,所以第32×[(23-1) ×94+(31-1)]=67136Bit以后的32個字節(jié)為“房”的字模信息玻熙。

代碼實現解析

要實現上面的滾動字幕的效果,可以分為如下幾步:

  1. 獲取文字字符串的字模信息疯攒,并且將字模信息轉化為Boolean類型的二維數組(字模信息的每一bit中0代表沒有嗦随,1代表有點,將0轉換成false敬尺,將1轉換為true)
    /**
     * 獲取漢字字符串的點陣矩陣
     * @param text
     * @return
     */
    public boolean[][] getWordsMatrix(Context context, String text) {
        return getWordsMatrix(context, text, null);
    }

    public boolean[][] getWordsMatrix(Context context, String text, DotMatrixFontType dotMatrixFontType) {
        if (null == dotMatrixFontType) {
            this.mDotMatrixFontType = DotMatrixFontType.SIXTEEN_TYPE;
            this.mWordByteByDots = DotMatrixFontType.SIXTEEN_TYPE.getValue() * DotMatrixFontType.SIXTEEN_TYPE.getValue() / 8;
        } else {
            this.mDotMatrixFontType = dotMatrixFontType;
            this.mWordByteByDots = dotMatrixFontType.getValue() * dotMatrixFontType.getValue() / 8;
        }

        byte[] bytes = null;
        try {
            // 獲取漢字文本的字節(jié)編碼
            bytes = text.getBytes(ENCODE);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        // 獲取每個字節(jié)對應正數編碼枚尼,即得到漢字對應的區(qū)碼和位碼
        int[] code = new int[bytes.length];
        for (int i = 0; i < bytes.length; i++) {
            code[i] = bytes[i] < 0 ? 256 + bytes[i] : bytes[i];
        }

        int wordNumber = code.length / 2;
        boolean[][] wordsMatrix = new boolean[mDotMatrixFontType.getValue()][mDotMatrixFontType.getValue() * wordNumber];
        for (int i = 0; i < wordNumber; i++) {
            // 通過區(qū)碼和位碼獲取字庫中對應的字模信息
            byte[] temp = read(context, code[2 * i], code[2 * i + 1]);
            for (int j = 0; j < mWordByteByDots; j++) {
                for (int k = 0; k < 8; k++) {
                    // 將字模信息轉化為Boolean類型的二維數組并且進行縱向填充數組
                    int row = (j * 8 + k) / 16 + i * mDotMatrixFontType.getValue();
                    int col = (j * 8 + k) % 16;
                    if (((temp[j] >> (7 - k)) & 1) == 1) {
                        wordsMatrix[col][row] = true;
                    } else {
                        wordsMatrix[col][row] = false;
                    }
                }
            }
        }

        return wordsMatrix;
    }

    /**
     * 從字庫中獲取指定區(qū)碼和位碼漢字的字模信息
     * @param areaCode 區(qū)碼,對應編碼的第一個字節(jié)
     * @param posCode  位碼滴某,對應編碼的第二個字節(jié)
     * @return
     */
    private byte[] read(Context context, int areaCode, int posCode) {
        byte[] data = null;
        try {
            int area = areaCode - 0xa0;
            int pos = posCode - 0xa0;
            InputStream in = context.getAssets().open(DOT_MATRIX_FONT);
            int offset = ((area - 1) * 94 + pos -1) * mWordByteByDots;
            in.skip(offset);
            data = new byte[mWordByteByDots];
            in.read(data, 0, mWordByteByDots);
            in.close();
        } catch (IOException e) {
            Log.d(TAG, "IOException e = " + e.getMessage());
        }
        return data;
    }
  1. 根據Boolean類型的二維數組繪制點陣车伞,當Boolean值為false项鬼,表示要繪制空心圓,反之繪制實心圓盯质。
    @Override
    protected void onDraw(Canvas canvas) {
        //super.onDraw(canvas);
        for (int row = 0; row < mDotMatrixFontType.getValue(); row++) {
            for (int col = 0; col < mDotMatrixFontType.getValue() * this.mWordNumber; col++) {
                if (mWordsMatrix[row][col]) {
                    canvas.drawCircle(col * (mPointSpace + mPaintRadius * 2) + mPointSpace + mPaintRadius,
                            row * (mPointSpace + mPaintRadius * 2) + mPointSpace + mPaintRadius,
                            mPaintRadius, mFillPaint);
                } else {
                    canvas.drawCircle(col * (mPointSpace + mPaintRadius * 2) + mPointSpace + mPaintRadius,
                            row * (mPointSpace + mPaintRadius * 2) + mPointSpace + mPaintRadius,
                            mPaintRadius, mHollowPaint);
                }
            }
        }
        Message message = new Message();
        message.obj = this.mScrollDirection;
        mHandler.sendMessageDelayed(message, mScrollSpeed.getValue());
    }
  1. 通過Handler機制實現定期刷新界面,即實現滾動效果概而。在上面的代碼最后唤殴,就是在繪制后向Handler發(fā)送一個延遲消息,從而進入到滾動循環(huán)到腥,下面是在Handler中通過調用invalidate方法實現定期刷新朵逝,即實現滾動的效果:
    Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch ((Direction)msg.obj) {
                case LEFT:
                    matrixMoveToLeft();
                    invalidate();
                    break;
                case RIGHT:
                    matrixMoveToRight();
                    invalidate();
                    break;
            }
        }
    };

    private void matrixMoveToRight() {
        for (int row = 0; row < mDotMatrixFontType.getValue(); row++) {
            boolean temp = mWordsMatrix[row][mDotMatrixFontType.getValue() * mWordNumber - 1];
            System.arraycopy(mWordsMatrix[row], 0, mWordsMatrix[row], 1, mDotMatrixFontType.getValue() * mWordNumber - 1);
            mWordsMatrix[row][0] = temp;
        }
    }

    private void matrixMoveToLeft() {
        for (int row = 0; row < mDotMatrixFontType.getValue(); row++) {
            boolean temp = mWordsMatrix[row][0];
            System.arraycopy(mWordsMatrix[row], 1, mWordsMatrix[row], 0, mDotMatrixFontType.getValue() * mWordNumber - 1);
            mWordsMatrix[row][mDotMatrixFontType.getValue() * mWordNumber - 1] = temp;
        }
    }

注意事項

  1. 將HZK16字庫放到assets文件夾中

參考文檔

  1. Android點陣屏效果的控件
  2. 漢字庫(HZK16)的使用
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市乡范,隨后出現的幾起案子配名,更是在濱河造成了極大的恐慌啤咽,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,290評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件渠脉,死亡現場離奇詭異宇整,居然都是意外死亡,警方通過查閱死者的電腦和手機芋膘,發(fā)現死者居然都...
    沈念sama閱讀 90,107評論 2 385
  • 文/潘曉璐 我一進店門鳞青,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人为朋,你說我怎么就攤上這事臂拓。” “怎么了习寸?”我有些...
    開封第一講書人閱讀 156,872評論 0 347
  • 文/不壞的土叔 我叫張陵胶惰,是天一觀的道長。 經常有香客問我霞溪,道長孵滞,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,415評論 1 283
  • 正文 為了忘掉前任鸯匹,我火速辦了婚禮坊饶,結果婚禮上,老公的妹妹穿的比我還像新娘殴蓬。我一直安慰自己幼东,他們只是感情好,可當我...
    茶點故事閱讀 65,453評論 6 385
  • 文/花漫 我一把揭開白布科雳。 她就那樣靜靜地躺著根蟹,像睡著了一般。 火紅的嫁衣襯著肌膚如雪糟秘。 梳的紋絲不亂的頭發(fā)上简逮,一...
    開封第一講書人閱讀 49,784評論 1 290
  • 那天,我揣著相機與錄音尿赚,去河邊找鬼散庶。 笑死,一個胖子當著我的面吹牛凌净,可吹牛的內容都是我干的悲龟。 我是一名探鬼主播,決...
    沈念sama閱讀 38,927評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼冰寻,長吁一口氣:“原來是場噩夢啊……” “哼须教!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,691評論 0 266
  • 序言:老撾萬榮一對情侶失蹤轻腺,失蹤者是張志新(化名)和其女友劉穎乐疆,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體贬养,經...
    沈念sama閱讀 44,137評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡挤土,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,472評論 2 326
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了误算。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片仰美。...
    茶點故事閱讀 38,622評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖儿礼,靈堂內的尸體忽然破棺而出咖杂,到底是詐尸還是另有隱情,我是刑警寧澤蜘犁,帶...
    沈念sama閱讀 34,289評論 4 329
  • 正文 年R本政府宣布翰苫,位于F島的核電站止邮,受9級特大地震影響这橙,放射性物質發(fā)生泄漏。R本人自食惡果不足惜导披,卻給世界環(huán)境...
    茶點故事閱讀 39,887評論 3 312
  • 文/蒙蒙 一屈扎、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧撩匕,春花似錦鹰晨、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至扁凛,卻和暖如春忍疾,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背谨朝。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工卤妒, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人字币。 一個月前我還...
    沈念sama閱讀 46,316評論 2 360
  • 正文 我出身青樓则披,卻偏偏與公主長得像,于是被迫代替她去往敵國和親洗出。 傳聞我的和親對象是個殘疾皇子士复,可洞房花燭夜當晚...
    茶點故事閱讀 43,490評論 2 348

推薦閱讀更多精彩內容

  • 背景 一年多以前我在知乎上答了有關LeetCode的問題, 分享了一些自己做題目的經驗。 張土汪:刷leetcod...
    土汪閱讀 12,737評論 0 33
  • 1. Java基礎部分 基礎部分的順序:基本語法翩活,類相關的語法判没,內部類的語法蜓萄,繼承相關的語法,異常的語法澄峰,線程的語...
    子非魚_t_閱讀 31,598評論 18 399
  • 一嫉沽、 1、請用Java寫一個冒泡排序方法 【參考答案】 public static void Bubble(int...
    獨云閱讀 1,353評論 0 6
  • 《和時間做朋友》這本書從2015年5月斷斷續(xù)續(xù)看到了2015年9月俏竞。很慶幸能遇見這本好書绸硕,作者很多觀點我很認同,經...
    小森林Sherry閱讀 693評論 0 1
  • 26號聽欣頻老師課時遇見了一位面熟的姐姐魂毁,見過玻佩,可又想不起在哪里有過一面之緣。之后在3月1號去紅丹丹文化助盲服務中...
    泉水咕咕咕閱讀 173評論 0 0