Emoji’s World, 一起實現Emoji?輸入吧!

Spike發表於2017-03-30

Emoji (絵文字 或 えもじ; 日語發音: [emodʑi]) 是日本無線通訊中所使用的視覺情感符號, 代表圖形, 文字是圖形本身的隱喻. 用於輸入者表達情感資訊, 如笑臉就代表開心?, 蛋糕就代表食物?等. 形象生動, 在文字中出現圖片, 更容易實現情感的表述.

Emoji起初只能在日本使用, 如今相當一部分的Emoji字符集已經被收入Unicode編碼, 使其能被廣泛應用. Android系統對於Emoji的原生支援從4.4版本開始. 對於文字輸入型應用而言, 自定義的Emoji表情會大幅提升使用者體驗, 增強使用者對於應用的辨識度, 也使輸入更加有趣. 原生的Emoji表情由於需要適配多款機型, 節省儲存空間, 所以設計得較為粗糙. 優秀美工重繪的Emoji表情, 一般都會更加符合使用者的視覺習慣, 這就是QQ和微信大量重繪Emoji的原因.

本文介紹Emoji表情的實現方式, 具體效果參考春雨醫生的線上問診頁面.

Emoji’s World, 一起實現Emoji?輸入吧!

Emoji

下載Emoji列表

Emoji表情資料的儲存方式有兩種, 第一種在本地, 隨著應用一起分發; 第二種在遠端, 訪問伺服器獲取. 顯然第二種更為合理, 易於修改和替換, 方便重繪Emoji表情的後續擴容. 從遠端伺服器中獲取Emoji資料時, 注意需要使用有序列表, 因為根據使用者的使用習慣不同, 有些常用表情在先, 有些不常用在後. 考慮列表的有序性, 選擇ArrayList-Pair資料結構傳輸, 而非Map, 因為列表是有序的, 而Map是無序的, 也可以選擇LinkedHashMap.

本例Emoji資料集的資料結構是ArrayList>, 其中Pair的Key是Emoji的Unicode字元, Value是Emoji表情的下載地址.

在獲取Emoji表情集合的全部表情下載地址後, 將這些表情快取至本地, 統一更新, 減少訪問遠端伺服器的次數, 節省流量和電量. 表情集合儲存在BitmapLruCache類中, 即LRU快取類, 其快取模組使用記憶體(Memory)與本地硬碟(Disk)的二級快取. 注意下載過程需要在非UI執行緒中進行, 即EmojiDownloadAsyncTasks.


快取Emoji資料

為了快速地訪問Emoji表情, 為其新增圖片快取必不可少. 本例的快取類是BitmapLruCache, 其內部使用常見的二級快取, 即記憶體快取和硬碟快取.

注意: 為了加快開發和減少錯誤, 儘量選擇複用已有的輪子. 記憶體快取使用Android系統自帶的LruCache; 外存快取使用DiskLruCache(Jake Wharton).

類中的addBitmapToCache方法, 將表情下載的url作為快取對映Map的唯一Key. 下載後的Bitmap, 會優先寫入外存快取, 再同步寫入記憶體快取.

類中的getBitmapFromCache方法, 根據唯一標識下載url, 獲取Bitmap. 優先從記憶體中獲取, 當記憶體快取不存在時, 從外存讀取, 再同步寫入記憶體; 當記憶體快取存在時, 直接返回.

注意: Emoji表情一般都使用較小尺寸, 當圖片載入入記憶體時, 防止圖片過大, 優先進行壓縮, 避免佔用記憶體過多, 產生OOM. 尺寸大小支援外部配置.


管理Emoji資料

本例使用EmojiFileManager類作為Emoji表情集合的管理器, 同時作為介面, 向外部提供資料和方法. 原始的有序列表轉換為無需對映HashMap, 便於快速查詢表情; 轉換為分頁列表, 使用List>匹配ViewPager的表情分頁顯示.

類中convertPairList2Map的方法, 將ArrayList-Pair資料結構轉換為HashMap, 加快Emoji表情的查詢速度.; 類中convertPairToPageList的方法, 將原始結構ArrayList-Pair, 組合成EmojiIcon的陣列, 再根據每頁顯示個數, 重構成二維陣列, 用於ViewPager的表情分頁顯示.


替換Emoji表情

在字串中, 替換Emoji表情的方式主要有兩種: 第一種是在已有字串中查詢已經存在的Emoji編碼, 替換為相應的表情; 第二種是建立單個Emoji表情的字串.

類中的getExpressionString方法, 設定查詢模式, 呼叫dealExpression替換相應Emoji表情, 並返回支援文字和圖片的組合的SpannableString型別.

注意: 在Pattern中設定Pattern.UNICODE_CASE引數, 使其僅檢查Unicode字串, 縮小範圍, 可以顯著提升匹配速度, 否則在字串較長時, 匹配速度較慢.

類中dealExpression方法查詢匹配字串, 呼叫addBitmap2Spannable替換圖片, 並遞迴解析剩下的字串, 直至全部替換完成. 具體步驟:

  1. 將所需替換的字串與Emoji的Unicode標準編碼匹配, 組成Matcher.
  2. 如果Matcher匹配成功, 則獲取相應的字串key.
  3. 如果Emoji字典中存在這個key, 則獲取Emoji的對應url.
  4. 如果url存在, 則呼叫addBitmap2Spannable替換字串為Emoji表情.
  5. 繼續遞迴呼叫, 解析剩下的字串.

類中的addBitmap2Spannable方法, 根據Emoji的url, 從圖片快取BitmapLruCache中獲取相應的表情(Bitmap), 建立居中對齊的VerticalImageSpan, 與文字組合成SpannableString.

預設的ImageSpan引數不包含居中顯示, 重寫getSizedraw方法, 使ImageSpan居中對齊於文字, 注意位置資料的設定.

類中的addIcon方法, 建立單個Emoji表情的字串. 通過addBitmap2Spannable方法, 將Emoji編碼字串替換為表情.


在需要替換Emoji表情的位置, 呼叫EmojiFileManagergetExpressionString方法, 將字串中的Emoji編碼替換為Emoji表情; 在需要新增Emoji表情的位置, 呼叫其addIcon方法獲取單個Emoji表情, 與已存在的字串, 拼接成最終字串.

效果如下:

Emoji’s World, 一起實現Emoji?輸入吧!

Emoji

為文字輸入型應用新增Emoji表情吧, 讓輸入獲得更多樂趣.

That’s all! Enjoy it!

請使用手機”掃一掃”x

打賞支援我寫出更多好文章,謝謝!

打賞作者

打賞支援我寫出更多好文章,謝謝!

Emoji’s World, 一起實現Emoji?輸入吧!

相關文章