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 表情已经达到了一千多个。

感兴趣的同学可以到这里查看所有表情对应的编码

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 configuration

Downloadable fonts 是 Android O 新增的一个功能,支持通过 google mobile service 远程拉取需要的字体库到本地来进行使用。

由于国内屏蔽了 Google Service ,所以这种方式在国内我们使用不了,这里我们就不做详细介绍了。

Bundled fonts configuration

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 组件:

android.support.text.emoji.widget.EmojiTextViewHelper
android.support.text.emoji.widget.EmojiEditTextHelper

示例代码:

自定义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,所以你可以放心大胆地去使用它。

这里是官方的 Demo 地址:
https://github.com/googlesamples/android-EmojiCompat

里面包含了 downloadable fonts 的使用,因为比较完善 ,所以就不放我自己的 Demo 啦,感兴趣的小伙伴赶紧去下载看看吧!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容