Emoji表情在Android平臺的應(yīng)用

每一個 emoji,就是一個 Unicode 字符。全世界的 emoji 都由統(tǒng)一碼聯(lián)盟(The Unicode Consortium)來投票選拔和公布,世界各地的人們可以向聯(lián)盟提交 emoji 提案。而統(tǒng)一碼聯(lián)盟的 emoji 規(guī)范,只是定義了某個字符的語義,再由 Emojipedia 這個網(wǎng)站對 emoji 進(jìn)行描述表達(dá),最后允許大家按照對描述的理解,自由地去設(shè)計圖案。

目前 iOS 15.4 和 Android 12L 所使用的最新版 Emoji 的正式名稱其實叫 Emoji 14.0,它是在 2021 年 9 月通過了 Unicode(統(tǒng)一碼)聯(lián)盟的批準(zhǔn)發(fā)布,然后才被 Google 和蘋果應(yīng)用在系統(tǒng)中。

??
Emoji名稱:嘿嘿
英文名稱:grinning face
unicode版本: 6.1
unicode編碼:U+1F600

一個 emoji 的版權(quán)細(xì)節(jié)可能設(shè)計多方的利益:

emoji 的官方名字版權(quán)屬于 Unicode 規(guī)范,即統(tǒng)一碼聯(lián)盟;
emoji 的描述文字版權(quán),屬于網(wǎng)站 emojipedia.org;
emoji 對應(yīng)的圖形設(shè)計版權(quán),屬于它的創(chuàng)作者或公司。

相同emoji編碼在不同平臺上的圖像

Android不同系統(tǒng)版本之間emoji互通問題

Emoji 在發(fā)送和接受方的不同顯示效果
Emoji 無法在不同 Android 版本間正確表達(dá)多樣性和包容性

在 Android 7.0 Nougat 和更早版本上無法正確通過 Emoji 表示膚色。用戶發(fā)送了一個表示深膚色手臂的 Emoji,但對方收到的卻是一個手臂和深色方塊的分解版本。
在 Android 8.0 Oreo 和更早版本上無法正確顯示代表中性的 Emoji。
在 Android 9 Pie 和更早版本上不支持顯示多人多膚色的 Emoji。

emoji 編碼規(guī)則

emoji modifier sequence (修飾序列)

????是一個Emoji修飾符序列,它由兩個Emoji組合而成,分別是:??(Emoji修飾符基礎(chǔ))和??(Emoji修飾符)。膚色Emoji修飾符共有5種,分別是:??, ??, ??, ??, ??。??可以與這些膚色Emoji修飾符結(jié)合形成新的Emoji序列,下面是組合的例子:

??(\ud83e\uddd1)????(\ud83e\uddd1\uD83C\uDFFE)

emoji zwj sequence (零寬連接序列, zwj=zero width joint)

????????(1F468 200D 1F469 200D 1F467 200D 1F467)是一個零寬連接符Emoji序列,它由3個ZWJ零寬度連接符和4個單獨Emoji組合在一起形成。這些單獨的Emoji分別是:?? (男人), ?? (女人), ?? (女孩), ?? (女孩)。組成的新Emoji在一些兼容性好的平臺中顯示為一個單獨的Emoji:????????,但在一些兼容性不好的平臺也可能顯示為多個放在一起的Emoji:????????

Emoji 渲染原理

一組碼點

Emoji 屬于一種圖形字符,是字符串的一部分。它就像字母 "I" 一樣,只是繪制方式和從屬的字體文件不同而已。但是對于計算機來說,它并不會特意關(guān)心什么是 Emoji 或字母 "I",一個字符串本質(zhì)上就只是一組碼點,其中的數(shù)字通過 Unicode 進(jìn)行分配,代表著計算機上會出現(xiàn)的每一個字符。

現(xiàn)在 Unicode 并不僅僅只是一種格式了,它還代表了制定該標(biāo)準(zhǔn)的委員會,委員會會決定一些事情,比如數(shù)字 7 代表字母 "I" (實際上 7 并非真正代表字母 I 的碼點,此處僅僅是舉個例子)。那么當(dāng)您試圖在 Android 上渲染上述表示字符串的碼點時會發(fā)生什么呢?

首先,Android 會根據(jù)碼點和應(yīng)用要求使用的字體樣式為每個字符找出最佳字體。當(dāng)前 Android 上非斜體且正常粗細(xì) "V" 的默認(rèn)字體是 roboto-regular.ttf,Android 會對字符串進(jìn)行遍歷,檢查每個字符并查找最佳字體。它會檢查碼點和樣式,您可以對字符串進(jìn)行樣式的定制操作,比如對一些字符進(jìn)行加粗等等。對于上述簡單的字符串來說,它就只是會選擇 roboto-regular.ttf 字體。

遍歷碼點查找正確的字符串

但是,當(dāng)遇到 Emoji 字符時,您可能會覺得它會進(jìn)行完全不同的渲染方式,畢竟它看起來不像任何其他的字母。但實際上,Emoji 就是個文本,由碼點表示,同字母 "I" 和 "I" 一樣沒什么區(qū)別,繪制它的方式就存儲到了字體中。Android 會首先嘗試在字體中查找無斜體且正常粗細(xì)的 "融化臉",但這一次發(fā)現(xiàn)在 roboto-regular 中并沒有想要的結(jié)果,便會去 NotoColorEmoji 中進(jìn)行查找,這是 AOSP 上預(yù)裝的 Emoji 字體,它包含了每個 Emoji 的圖像,在 Android 平臺上通過這種字體繪制 Emoji 和繪制字母 "I" 的方式完全相同,都是查找字體文件后在屏幕上繪制出來。

通過 NotoColorEmoji 對 Emoji 字符進(jìn)行繪制

在 Android 12 及以上版本中,平臺可以確保 Emoji 會正常顯示,因為可更新系統(tǒng)字體會將新版 Emoji 添加到字體文件中。但對于 Android 12 之前的版本,我們沒有任何方法可以更新字體,這意味著 Android 不知道用什么字體來繪制 "融化臉",此時它會改為繪制一個稱為豆腐塊的備用字形。這里就是 Emoji2 開始大展身手的地方了。

Emoji2 對 Emoji 字符的繪制過程

在將字符串發(fā)送到 Android 系統(tǒng)之前,在字符串上會調(diào)用 EmojiCompat.process 方法,此調(diào)用將遍歷并查找那些系統(tǒng)不知道如何繪制的 Emoji,并為每個 Emoji 添加一個 EmojiSpan,這是一個替換 Span,這意味著它將只替換該段字符串中對應(yīng)的內(nèi)容。系統(tǒng)會直接使用 roboto-regular.ttf 正常繪制,但當(dāng)找到 EmojiSpan 時它會將繪制權(quán)轉(zhuǎn)交給 Span。

在該 Span 中 Android 使用了兩個方法,首先,它會獲取字符尺寸并告訴 Android 要在文本布局中為此 Span 保留多少空間,然后,當(dāng)需要繪制字符串時,它將調(diào)用 EmojiSpan 上的 draw 而非自行繪制。在 EmojiSpan 中,它知道 Compat 版的 Emoji 字體位置,并能直接從中繪制出 "融化臉"。再返回到渲染階段,平臺將調(diào)用 EmojiSpan.draw,整個區(qū)域?qū)⒂?EmojiSpan 進(jìn)行繪制,而非平臺。實際上,從平臺的角度來看 EmojiSpan 只是在字符串中間繪制了一張圖片,并沒有別的特殊操作。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容