1. 程式人生 > >Android 官方相容庫 EmojiCompat Support Library

Android 官方相容庫 EmojiCompat Support Library

什麼是 emoji?

emoji 是一種 表情符號,來自日語詞彙“絵文字”(假名為“えもじ”,讀音即 emoji)

它的創造者是日本人慄田穰崇 ( Shigetaka Kurita ) ,他將目光投向兒時的各種元素以獲取靈感,如日本漫畫和日本漢字等。“日本漫畫中有許多不同的符號。漫畫家會畫出一些表情,表現一個人滿頭大汗或是迸發出一個想法時頭上出現一個燈泡。”同時,從日本漢字中他獲得了一種能力,用簡單的字元來表達“祕密”和“愛”等抽象概念。

image.png

早期的 emoji 表情並沒有一套統一的規範,日本的三大電信運營商,NTT DoCoMo,au/KDDI,Softbank 都各自有一套關於 Emoji 的編碼規範,導致運營商使用者之間傳送 emoji 表情時無法顯示。

直到2010年10月,隨著 Unicode6.0 的釋出,Emoji 的編碼以及對應的表情圖片正式被規範化,核心 Emoji 表情包含722個 Emoji 編碼。

之後 2014年6月15日釋出的 Unicode 7.0 規範以及 2016年6月22日釋出的 Unicode 9 規範都不斷地加入新的 emoji 表情,目前整個 emoji 表情已經達到了一千多個。

感興趣的同學可以到這裡檢視所有表情對應的編碼

Android 對 emoji 表情的相容

很多同學可能並沒有注意到 Android 裝置上的 Emoji 表情

一般情況下,我們在手機上進行操作時, 只有使用了輸入法自帶的表情及 emoji 表情才會在文字中產生 emoji 編碼。

image.png

image.png

在 Android 4.4 之前, Android 並不支援 emoji 表情,當時的解決方案主要是通過 imageSpan 配合 spannableString,來替換掉文字中的 emoji unicode 編碼符號。

從 Android 4.4 開始, 官方開始了 emoji 表情的支援,實現原理基本就是通過把 emoji 表情內建在系統的 ttf 字型庫中,對文字進行過濾後顯示出 emoji 表情。

由於不同 Android 版本內建的 ttf 字型庫對 emoji 表情的版本支援程度不同,導致老版本的 Android 對最新的 emoji 表情支援不全,所以一些 在新的 unicode 版本規範中被加入的 emoji 表情在老的 Android 裝置上會顯示方框亂碼。

為了處理這個問題,除去上文提到的 spannable 的處理方案,我們還可以通過定義自己的 ttf 字型庫給文字空間指定字型來顯示 emoji 表情。

EmojiCompat Support Library 的誕生

正是由於上文提到的相容問題,Google 官方的 EmojiCompat Support Library 誕生了。

目前這個庫能向下相容到 Android 4.4,其主要目標就是為了讓我們的 Android 裝置能夠支援最新的 emoji 表情,防止最新的 emoji 表情在我們的手機上顯示為☐。

Emoji 對照

EmojiCompat 通過 CharSequence 文字中的 emoji 對應的 unicode 編碼來識別 emoji 表情,將他們替換成 EmojiSpans ,最後再將 EmojiSpan 渲染成對應的 emoji 表情符號。

emojiCompat處理過程

對於 EmojiCompat 的使用,有兩種配置方式:

Downloadable fonts 是 Android O 新增的一個功能,支援通過 google mobile service 遠端拉取需要的字型庫到本地來進行使用。

由於國內遮蔽了 Google Service ,所以這種方式在國內我們使用不了,這裡我們就不做詳細介紹了。

Bundled fonts 即打包字型,就是使用本地打包好的 emoji 字型庫來相容 emoji 表情。

目前官方使用的是 NotoColorEmojiCompat.ttf 字型檔案。

EmojiCompat 的使用

接下來我們來看看如何使用 emojiCompat 庫

新增依賴庫

首先我們在 build.gradle 中配置我們的依賴包,由於我們使用的是 Bundled fonts 的配置,所以我們需要先引入我們的 emoji bundle 庫:

dependencies {
    ...
    compile "com.android.support:support-emoji-bundled:$version"
}

這裡我 $version 設定的版本是 26.0.0-beta1,如果編譯過程中提示找不到依賴庫,需要在 repositories 倉庫配置中加入 Google 的 maven 地址:

allprojects {
    repositories {
        jcenter()
        maven { url 'https://maven.google.com' }
    }
}

接著我們引入 EmojiCompat 的元件庫:

dependencies {
    ...
    compile "com.android.support:support-emoji:26.0.0-beta1"
}

該元件庫對應的 emojiCompat 元件:

<android.support.text.emoji.widget.EmojiTextView
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"/>

<android.support.text.emoji.widget.EmojiEditText
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"/>

<android.support.text.emoji.widget.EmojiButton
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"/>

如果你使用的是 AppCompat 庫, 也可以直接新增 emojiCompat 的 compat 元件庫

dependencies {
      compile "com.android.support:support-emoji-appcompat:26.0.0-beta1"
}

該引用庫對應的元件:

<android.support.text.emoji.widget.EmojiAppCompatTextView
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"/>

<android.support.text.emoji.widget.EmojiAppCompatEditText
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"/>

<android.support.text.emoji.widget.EmojiAppCompatButton
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"/>

compat 庫跟非 compat 庫之間的差別主要就是在使用的元件名稱上,其他的方式基本一致。

初始化 EmojiCompat

在正式使用 EmojiCompat 之前我們還需要對其進行初始化

public class MyApplication extends Application {
@Override
    public void onCreate() {
       super.onCreate();
       EmojiCompat.Config config = new BundledEmojiCompatConfig(this);
       EmojiCompat.init(config);
    }
}

此時我們便可以使用上一步新增的 emojiCompat 元件來替換原有的 TextView、 EditText 以及 Button 元件了,當文字中遇到對應的 emoji 表情編碼時就會自動替換為 emoji 表情了。
device-2017-06-30-134851.png

不通過元件使用 emojiCompat 相容庫

EmojiCompat 庫通過 EmojiSpan 來渲染正確的表情圖片,因此需要先將文字 CharSequence 根據 emoji 編碼轉換成對應的 EmojiSpan Spanned 例項。

EmojiCompat 專門提供了一個 process() 方法用於CHarSequence 例項的轉換

使用這種方法,我們可以快取處理過的例項而不是原始字串,在需要使用的地方直接呼叫該例項,從而提高應用程式的效能。

TextView regularTextView = findViewById(R.id.regular_text_view);

CharSequence processed = EmojiCompat.get().process("neutral face \uD83D\uDE10");

regularTextView.setText(processed);

自定義 EmojiCompat 元件

除了上面提到的通過 EmojiCompat 的 process 方法轉換 spanned 例項外,我們還可以通過官方提供的兩個 widget helper 類來自定義我們的 TextView 以及 EditTextView 元件:

示例程式碼:

自定義Emoji TextView

public class MyTextView extends AppCompatTextView {
   ...
   public MyTextView(Context context) {
       super(context);
       init();
   }
   ...
   private void init() {
       getEmojiTextViewHelper().updateTransformationMethod();
   }

   @Override
   public void setFilters(InputFilter[] filters) {
       super.setFilters(getEmojiTextViewHelper().getFilters(filters));
   }

   @Override
   public void setAllCaps(boolean allCaps) {
       super.setAllCaps(allCaps);
       getEmojiTextViewHelper().setAllCaps(allCaps);
   }

   private EmojiTextViewHelper getEmojiTextViewHelper() {
       ...
   }
}

自定義 Emoji EditText

public class MyEditText extends AppCompatEditText {
   ...
   public MyEditText(Context context) {
       super(context);
       init();
   }
   ...
   private void init() {
       super.setKeyListener(getEmojiEditTextHelper().getKeyListener(getKeyListener()));
   }

   @Override
   public void setKeyListener(android.text.method.KeyListener keyListener) {
       super.setKeyListener(getEmojiEditTextHelper().getKeyListener(keyListener));
   }

   @Override
   public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
       InputConnection inputConnection = super.onCreateInputConnection(outAttrs);
       return getEmojiEditTextHelper().onCreateInputConnection(inputConnection, outAttrs);
   }

   private EmojiEditTextHelper getEmojiEditTextHelper() {
       ...
   }
}

總結

看了上面的使用步驟,EmojiCompat 的使用是不是很方便呢?

目前來說,EmojiCompat 只相容 Android 4.4 以上的裝置,對於 4.4 以下的裝置,它的行為跟普通的 Android 元件沒有差異。

EmojiCompat 的初始化時間大約只需要 150 毫秒,記憶體的佔用大概在200kb,所以你可以放心大膽地去使用它。

裡面包含了 downloadable fonts 的使用,因為比較完善 ,所以就不放我自己的 Demo 啦,感興趣的小夥伴趕緊去下載看看吧!