還在為Android表情開發煩惱嗎,快來試試Android Emoji吧

xiangzhihong發表於2021-12-29

一、什麼是 Emoji

1.1 Emoji背景

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

早期的 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 14.0,整個 Emoji 表情也達到了3600多個。具體細節可以檢視unicode官網

在這裡插入圖片描述
不過,雖然 Emoji 已經被標準化,但是不同平臺因為使用的字型不同,導致同樣的 Unicode 代表的 Emoji,被渲染顯示出來的效果也會不一樣,如下。
在這裡插入圖片描述

1.2 Android 對 Emoji 的支援

在 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,目前這個庫能向下相容到 Android 4.4,其主要目標就是為了讓我們們的 Android 裝置可以支援最新的 emoji 表情,防止最新的 emoji 表情在我們們的手機上顯示為☐。EmojiCompat 經過 CharSequence 文字中的 emoji 對應的 unicode 編碼來識別 emoji 表情,將他們替換成 EmojiSpans ,最後再將 EmojiSpan 渲染成對應的 emoji 表情符號。

二、EmojiCompat

2.1 什麼是EmojiCompat

EmojiCompat 是 Google 官方給我們提供的一個 Emoji 表情相容庫,最低支援到 Android 4.4(Api Level 19) 的系統裝置,它可以防止應用中,出現以信封的形式來顯示 Emoji,雖然它僅僅只是因為你當前的裝置沒有這個字型而已。通過 EmojiCompat ,你的裝置無需等待 Android 系統更新,就可以獲得最新的 Emoji 表情顯示效果,原理如下。

在這裡插入圖片描述
可以看到,Emoji的一個顯示原理,EmojiCompat 會判斷當前裝置是否支援這個 Emoji,如果支援則還是使用系統內建的字型載入,如果不支援,則使用 EmojiSpan 來進行替換,從而達到替換渲染的效果。

2.2 配置 EmojiCompat

EmojiCompat 提供兩種字型的支援方式,它們分別是可下載的字型配置和本地捆綁的字型配置。

  • 可下載的字型配置:可下載的字型的方式會在首次啟動 app 的時候檢查本地是否有該字型,沒有的話會從網上下載最新的 Emoji 字型,然後遇到不支援的 Emoji,就會從這個字型檔案中,載入資源並且渲染。
  • 本地捆綁的字型配置:本地捆綁的方式會在 App 打包的過程中,植入一個最新的 Emoji 字型檔案,然後遇到不支援的 Emoji,就會從這個字型檔案中,載入資源並且渲染。

2.2.1 本地字型配置方式

首先,需要在 build.gradle新增emoji-bundled依賴,如下。

implementation 'androidx.emoji:emoji-bundled:1.1.0'

然後,初始化 構建本地捆綁字型配置EmojiCompat,由於初始化是耗時的,所以最好提前進行初始化,比如Application中。

class MyApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        initEmoji()
    }

    private fun initEmoji() {
        val config: EmojiCompat.Config = BundledEmojiCompatConfig(this)
        config.setReplaceAll(true)
        config.registerInitCallback(object : InitCallback() {
            override fun onInitialized() {
                //初始化成功回撥
            }

            override fun onFailed(@Nullable throwable: Throwable?) {
                //初始化失敗回撥
            }
        })
        EmojiCompat.init(config)
    }
}

2.2.2 可下載的字型配置

可下載的字型需要在 build.gradle新增emoji依賴,如下。

implementation 'androidx.emoji:emoji:1.1.0'

然後,構建可下載字型配置初始化 EmojiCompat,初始化的時候需要傳入字型,如下。

private fun initEmojiCompat() {
        val fontRequest = FontRequest(
            "com.google.android.gms.fonts",
            "com.google.android.gms",
            "Noto Color Emoji Compat",
            R.array.emoji_list
        )
        val config: EmojiCompat.Config = FontRequestEmojiCompatConfig(this, fontRequest)
        config.setReplaceAll(true)
        config.registerInitCallback(object : InitCallback() {
            override fun onInitialized() {
                //初始化成功回撥
            }

            override fun onFailed(throwable: Throwable?) {
                //初始化失敗回撥
            }
        })
        EmojiCompat.init(config)
    }

2.3 使用EmojiCompat

初始化之後,接下來就是在業務開發中使用EmojiCompat。EmojiCompat 的處理邏輯,前面已經講的很清楚了:首先,它會載入一個 Emoji 字型,然後判斷當前裝置是否支援需要顯示的 Emoji,如果不支援,則使用 EmojiSpans 替換它,最終將處理過的 CharSequence 設定到 TextView 上。而這個過程,EmojiCompat 提供了一個process()方法。
在這裡插入圖片描述

從程式碼中可以看到,process()接受一個 CharSequence 並處理它,然後返回一個 CharSequence。舉個例子:我們使用process()轉換一個笑臉的表情。

EmojiCompat.get().process("笑臉: \uD83D\uDE01")

在實際專案中,如果每次都需要通過 EmojiCompat.get().process() 對字串進行處理,其實挺麻煩的。為此,EmojiCompat 提供了EmojiTextView,EmojiButton,EmojiEditText等控制元件。

<androidx.emoji.widget.EmojiTextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="&#129316;" />

    <androidx.emoji.widget.EmojiButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="&#10084;" />

    <androidx.emoji.widget.EmojiEditText
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="&#128527;" />

EmojiCompat 會判斷當前裝置是否支援這個 Emoji,如果支援則還是使用系統內建的字型載入,如果不支援,則使用 EmojiSpan 來進行替換,從而達到替換渲染的效果。這是在你沒設定 config.setReplaceAll(true) 的情況下,而如果你設定了 config.setReplaceAll(true) ,那麼所有的 Emoji 表情都會使用 EmojiSpan 替換並渲染。

2.4 自定義Emoji控制元件

當然,我們也可以自定義Emoji控制元件,自定義Emoji控制元件可以參考下EmojiAppCompatTextView 和 EmojiAppCompatEditView 中的實現。
在這裡插入圖片描述

三、Emoji2

由於之前的版本EmojiCompat 只相容 Android 4.4 以上的裝置,對於 4.4 如下的裝置它的行為跟普通的 Android 元件是沒有差別的。並且,EmojiCompat 的初始化時間大約只須要 150 毫秒,記憶體的佔用大概在200kb,所以最近Google官方提供了Emoji2庫。使用之前,需要先新增依賴,如下。

    def emoji2_version = "1.0.0"
    implementation "androidx.emoji2:emoji2:$emoji2_version"
    implementation "androidx.emoji2:emoji2-views:$emoji2_version"
    implementation "androidx.emoji2:emoji2-views-helper:$emoji2_version"

Emoji2一共提供了4個控制元件,EmojiButton、EmojiEditText、EmojiExtractTextLayout和EmojiTextView,使用方式和之前的差不多,比如。

<androidx.emoji2.widget.EmojiTextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="&#129316;"
        tools:ignore="MissingConstraints" />

    <androidx.emoji2.widget.EmojiButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="&#10084;"
        tools:ignore="MissingConstraints" />

    <androidx.emoji2.widget.EmojiEditText
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="&#128527;"
        tools:ignore="MissingConstraints" />

既然Emoji這麼有趣,還不快在你的應用中使用 AppCompat 1.4。

相關文章