27
2017
09

Android 8.0 新特性(三) - 表情符号兼容性


原文地址:Emoji Compatibility

EmojiCompat支持库目的在于使Android设备与最新的表情符号保持同步。它避免了应用程序以’☐’的形式取代缺少的表情符号字符,这表示设备没有显示文本的字体。通过使用EmojiCompat支持库,应用用户不需要通过更新Android操作系统来获取最新的表情符号。

这里写图片描述

EmojiCompat如何工作?

EmojiCompat支持库提供类,以便在运行Android 4.4(API 19)或更高版本的设备上实现支持向后兼容的表情符号。可以使用绑定或可下载的字体配置EmojiCompat。有关配置相关信息,可参考后续介绍的:

  • 可下载的字体配置
  • 绑定的字体配置

EmojiCompat为给定的CharSequence标识表情符号,如果有需要,将其替换为EmojiSpans,并最终显示表情符号。如下图所示:

这里写图片描述

可下载的字体配置

可下载的字体配置使用可下载的字体支持库特性来下载表情符号字体。它还更新了EmojiCompat支持库所需要的必要的表情符号元数据,以与最新版本的Unicode规范同步。

添加支持库依赖关系

要使用EmojiCompat支持库,必须将支持库的依赖关系添加至工程。

  1. 打开app的build.gradle文件。
  2. 添加依赖关系

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

初始化可下载的字体配置

需要初始化EmojiCompat以加载元数据和字体。由于初始化可能需要一些时间,初始化过程在后台线程上运行。

要使用可下载的字体配置初始化EmojiCompat,按照以下步骤执行:

  1. 创建一个FontRequest类的实例,并提供字体提供者权限,字体提供程序包,字体查询以及证书的Hash列表。 有关FontRequest的更多信息,可参考Downloadable Fonts
  2. 创建一个FontRequestEmojiCompatConfig类的实例,并提供Context和FontRequest类实例
  3. 通过调用init()方法并传递FontRequestEmojiCompatConfig的实例来初始化EmojiCompat。

    public class MyApplication extends Application {
      @Override
       public void onCreate() {
         super.onCreate();
         FontRequest fontRequest = new FontRequest(
           "com.example.fontprovider",
           "com.example",
           "emoji compat Font Query", CERTIFICATES);
           EmojiCompat.Config config = new FontRequestEmojiCompatConfig(this, fontRequest);
           EmojiCompat.init(config);
       }
    }
    
  4. 在布局XML中使用EmojiCompat控件。如果使用AppCompat,可参考后续的[使用带有AppCompat控件的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"/>
    

Github代码示例地址:googlesamples/android-EmojiCompat

支持库组件

这里写图片描述

  • Widgets: EmojiEditText, EmojiTextView, EmojiButton,默认的控件,其为带有EmojiCompat的TextView、EditText和Button
  • EmojiCompat:支持库的主要公共接口。它执行所有外部调用,并与系统的其他部分进行协调。
  • EmojiCompat.Config:配置要创建的单例实例
  • EmojiSpan:ReplacementSpan的子类,它将替换字符(序列),并呈现表情符号。
  • EmojiCompat Font:EmojiCompat使用字体显示表情符号。 这个字体是Android Emoji字体的修改版本。 字体修改如下:

    • 为了提供向后兼容性来呈现表情符号,所有的表情符号字符都在 Unicode’s Supplemental Private Use Area-A 中使用一个Unicode编码点,并以U+F0001开头。
    • 额外的表情符号元数据以二进制格式插入到字体中,并在运行时由EmojiCompat解析。数据嵌入在字体的元表中,使用私有标签Emji。

配置选项

可以使用EmojiCompat实例来修改EmojiCompat行为。 可以使用基类中的以下方法设置配置:

  • setReplaceAll():确定EmojiCompat是否应该用EmojiSpans替换所有发现的表情符号。默认情况下,EmojiCompat会尽力了解系统是否可以显示表情符号,并且不会替换表情符号。 当设置为true时,EmojiCompat将使用EmojiSpans替换所有发现的表情符号。
  • setEmojiSpanIndicatorEnabled():EmojiCompat是否可以用EmojiSpan替换表情符号。当设置为true时,EmojiCompat绘制了EmojiSpan的背景。 该方法主要用于调试。
  • setEmojiSpanIndicatorColor():设置EmojiSpan的颜色。 默认值为GREEN。
  • registerInitCallback():EmojiCompat初始化的相关回调


EmojiCompat.Config config = new FontRequestEmojiCompatConfig(...)
       .setReplaceAll(true)
       .setEmojiSpanIndicatorEnabled(true)
       .setEmojiSpanIndicatorColor(Color.GREEN)
       .registerInitCallback(new InitCallback() {...})

添加初始化监听

EmojiCompat和EmojiCompa类提供registerInitCallback()和unregisterInitCallback()方法来注册/取消一个初始化回调。要调用这些方法,需要创建EmojiCompat.InitCallback实例。调用这些方法并传递EmojiCompat.InitCallback实例。当EmojiCompat支持库的初始化成功时,EmojiCompat类将回调onInitialized()方法。 如果库无法初始化,EmojiCompat类将回调onFailed()方法。

要检查任何时候的初始化状态,调用getLoadState()方法。 它的返回值如下:

  • LOAD_STATE_LOADING
  • LOAD_STATE_SUCCEEDED
  • LOAD_STATE_FAILED

EmojiCompat与AppCompat控件组合使用

如果正在使用AppCompat控件,则可以使用从AppCompat控件扩展的EmojiCompat控件。

  1. 添加依赖关系

    dependencies {
      compile "com.android.support:support-emoji-appcompat:$version"
    }
    
  2. 在布局XML中使用 EmojiCompat AppCompat 控件

    <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"/>
    

绑定字体配置

EmojiCompat支持库还提供绑定字体版本。此包包含具有嵌入元数据的字体。该包还包含一个BundledEmojiCompatConfig类,它使用AssetManager来加载元数据和字体。

字体的大小是多少兆字节。

添加依赖关系

如果想在绑定字体中使EmojiCompat,必须添加相应的依赖关系:

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

使用绑定字体配置EmojiCompat

要使用绑定字体配置EmojiCompat,按照以下步骤执行:

  1. 使用BundledEmojiCompatConfig创建一个EmojiCompat的实例,并提供一个Context的实例。
  2. 调用init()方法初始化EmojiCompat,并提供BundledEmojiCompatConfig.

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

没有控件时使用EmojiCompat

EmojiCompat使用EmojiSpan渲染正确的图像。因此,它必须使用EmojiSpans将任何给定的CharSequence转换为Spanned实例。 EmojiCompat类提供了一个使用EmojiSpans将CharSequences转换为Spanned实例的方法。调用此方法,可以处理和缓存处理后的实例而不是原始字符串,从而提高应用程序的性能。

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

在输入法(IME)中使用EmojiCompat

使用EmojiCompat支持库,键盘可以渲染正在交互的应用程序支持的表情符号。IME可以使用hasEmojiGlyph()方法来检查EmojiCompat是否能够呈现表情符号。hasEmojiGlyph()方法将接收一个表情符号的 CharSequence,如果EmojiCompat可以检测并呈现表情符,那么将返回true。

键盘还可以检查应用程序支持的EmojiCompat支持库的版本,以确定在调色板中要呈现的表情符号。要检查版本,如果可用,键盘需要检查EditorInfo.extras bundle中是否存在以下key:

  • EDITOR_INFO_METAVERSION_KEY:如果key存在于bundle中,则该值表示应用程序使用的表情符号元数据的版本。 如果此键不存在,该应用程序不使用EmojiCompat。
  • EDITOR_INFO_REPLACE_ALL_KEY:如果该key存在并设置为true,则表示应用程序已调用SetReplaceAll()方法。

在EditorInfo.extras bundle中接收到key后,键盘可以调用hasEmojiGlyph()方法,其中metadataVersion是EDITOR_INFO_METAVERSION_KEY的值,以检查应用程序是否可以呈现特定的表情符号。

在传统控件中使用EmojiCompat

可以随时使用process()方法来预处理应用程序中的CharSequence,并将其添加到可用渲染Spanned的控件中,比如,TextView。另外,EmojiCompat还提供了控件辅助类,以便自定义支持表情符号的控件。

  • EmojiTextViewHelper

    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() {
             if (mEmojiTextViewHelper == null) {
                 mEmojiTextViewHelper = new EmojiTextViewHelper(this);
             }
             return mEmojiTextViewHelper;
       }
    }
    
  • EmojiEditTextHelper

    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() {
    
          if (mEmojiEditTextHelper == null) {
              mEmojiEditTextHelper = new EmojiEditTextHelper(this);
          }
          return mEmojiEditTextHelper;
       }
    
    }
    
上一篇:OpenWrt源码分析之libubox 下一篇:Segue传递数据