Android 官方兼容库 EmojiCompat Suppor

作者: 香辣牛肉面 | 来源:发表于2017-06-30 16:42 被阅读3846次

    什么是 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 啦,感兴趣的小伙伴赶紧去下载看看吧!

    相关文章

      网友评论

      • Android_大船:求助。
        之前的问题(在Demo基础上修改)解决了,但是现在遇到了一个新的问题,我重建了一个Project,没有用EmojiTextView,用的是Textview,然后CharSequence processed = EmojiCompat.get().process("neutral face \uD83D\uDE10");
        regularTextView.setText(processed);
        Application中也初始化了,但是最后却报没有初始化异常。
        Caused by: java.lang.IllegalStateException: Not initialized yet
        香辣牛肉面:@Android_大船 这么奇葩,这个得具体看下代码了,我这没这个问题呢
        Android_大船:@香辣牛肉面 打断点的时候会执行,并且可以成功显示,但是不打断点就beng了。
        香辣牛肉面:没执行这个么
        EmojiCompat.Config config = new BundledEmojiCompatConfig(this);
        EmojiCompat.init(config);
      • Android_大船:求助!google的例子中woman对应U+1F469,查看Demo发现它用的值为:"\uD83D\uDC69\u200D\uD83D\uDCBB",可是我在用中文转Unicode时得到的结果却是:“\u0031\u0046\u0034\u0036\u0039”,不知道怎么才能正确转换。
        香辣牛肉面:@Android_大船 现在是怎么转的?
        Android_大船:@香辣牛肉面 可能我表达的不对。
        比如我的emoji表情对应的Unicode是U+1F469,我应该怎么转换成“\uD83D\uDC69\u200D\uD83D\uDCBB”。
        因为我看google的Demo中的写法不是U+1F469,而是“\uD83D\uDC69\u200D\uD83D\uDCBB”。
        香辣牛肉面:中文转换什么意思?
      • 泡沫_lhy:你好 我也一直报导包错误 该加的都加了 请问有解决方法了吗
        香辣牛肉面:你这翻墙了吗?gradle版本是多少
        泡沫_lhy:@笨笨猪_f226 我也是:pensive:
        cbd4a9660726:你的好了没,我都弄了快一天了,也是一直报错
      • buop:我在导库的时候一直提示导入错误,让我安装什么也是安装失败,让我检查一下网络,我已经翻墙了 应该不是网络的问题吧,请教一下这个问题怎么解决。谢谢
        香辣牛肉面:@buop 嗯
        buop:@香辣牛肉面 是 project的build.gradle文件里的
        allprojects {
        repositories {
        jcenter()
        maven { url 'https://maven.google.com' }
        }
        }
        这段吗
        香辣牛肉面:maven { url 'https://maven.google.com' }这个在repotistroy加了没
      • Dream_09fe:顶顶顶,支持面哥
      • 陆地蛟龙:面哥 果然厉害。么么哒。
      • BillyLu1994:面哥,我也要转
      • 因帅被判刑:大佬我能转载吗
        魂狐:请问,这个选择后出来的表情效果跟手机显示的不一致是怎么回事呢?
        香辣牛肉面:@因帅被判刑 随便转:relieved:

      本文标题:Android 官方兼容库 EmojiCompat Suppor

      本文链接:https://www.haomeiwen.com/subject/vvkmcxtx.html