Android Emoji
对于在网络聊天中表现不好的人来说,“表情”的诞生是上帝赐予的东西。表情的话,好像可以演感情自由变化的年轻人。
我们现在用的很多,不管是EMOR还是图形表情包,不难发现,很多表情追求仪式感,重视意思和实时体验,大多数都是重现面部表情和肢体动作,用一种“模拟”的身体在现场。
微信表情的玫瑰花带着长长的花梗发送或接收,都像是“抓住”的代入感。拥抱是漫画形象,可以在安慰的背景下操作的表现,可以看作是发送者的手臂或接收者的双臂。这种表情弥补了网络传播中无法感知情感变化的缺陷。
解读 emoji
《Emozi》有176个符号,快乐、吐舌头、亲吻、眨眼、闭嘴等。这些符号在网络和手机上都可以看到。2014年,用统一的版本统一所有代码标准后,推出了250个新的emoji表情,使其在互联网上应用更加舒适。
2014年8月,有牛津词典,编辑了这个表情包。这意味着这些表情符号将成为正式词汇,在以后的生活和工作中广泛使用。苹果收藏了这种表情后,网络上有更多的用户使用了表情包,现在已经风靡全球。这个表情比前面提到的更广泛,很多人都在使用。
Emoji的实用性
从这种表情看非常现实的生活;例如,心情不好的时候可以做哭的表情。就像平时的心情一样,笑脸、友好也意味着礼仪,但是表情的笑脸很特别,稍微往下看就会给人一种有意义的感觉,所以特别有趣。
和女朋友或妻子说话时可能会伤透心。虽然现在证明此时此刻在想念对方,但有些网友不知道为什么这种表情没有悲心,因为比起内心,这是现在流行的手势,所以很多年轻网友在网络平台上留言,希望以后会出现这一手势,期待不久的将来会更新。
在很多表情中最受欢迎的是红心。这红色的爱情代表爱情,代表期待,也有很多人用这种表情表示感谢。这表情给人的感觉很有礼貌。情侣之间的使用代表思念,代表浪漫。朋友之间的使用意味着友谊更近
母猪表情包介绍
以下是Emoji表情包的概述。
Emoji是可以插入到文本中的图形符号,是日语。e代表“画”,moji代表“文字”,连接的是“画文字”,这是第一次我们发送文字来提高用户的体验,2007年苹果在Apple上支持Emoji,使其在全球流行。
到2010年,Emoji很难通过用:等照片表达形式替换几种特殊的符号组合来标准化Emoji表情,表达范围受到限制。
从2010年开始,unicode开始为Emoji分配固定代码点。也就是说,此后,每个unicode字符都对应于一种字体,并渲染为图片显示
Emoji表情因为感情表达的特点而很受欢迎。Emoji表情的国际标准于2015年出台,目前为止是V13.1版本的标准。
需求
对Emoji表情有了大致的了解后,产品向我提出的要求之一是:其中,筛选出几种常见的Emoji表情,然后根据UI设计草案实现表情包功能即可。(注:emoji表情包、表情包、表情包、表情包、表情包、表情包、表情包)
上图中可以看到。
每个表情的unicode字符
说明unicode。unicode是一种统一的字符编码标准,当需要表示unicode字符时,通常u后跟一个十六进制数字(如上图所示)
与每个unicode字符相对应的Emoji表情因平台而异。因为unicode只规定了Emoji的代码点和含义,没有规定其样式。每个平台都有自己的Emoji实现
Emoji表情包练习
想起来了,就拿起柚子梗,开始把选定的表情代码放在一个地方。
然后通过 ViewPager + Fragment + RecyclerView 等一系列控件的配合,实现了 UI 需要的效果如下图:
从上图可以发现一个问题:有些 Emoji 表情显示出来像一个信封
原因是当前设备不支持,上面我讲到每一个 Unicode 字符对应一个字体,它会被渲染为图片显示,但是如果当前系统不支持这种字体,那么就会显示出一个信封,而且随着 Android 版本越来越低,这种情况越来越多,这种效果肯定是不行的
知道了出现的问题和原因,我们就要去想解决方法,这个时候 EmojiCompat 就来了
EmojiCompat 介绍
什么是 EmojiCompat ?
EmojiCompat 是 Google 官方给我们提供的一个 Emoji 表情兼容库; 最低支持到 Android 4.4(Api Level 19) 的系统设备,它可以防止应用中,出现以信封的形式来显示 Emoji,虽然它仅仅只是因为你当前的设备没有这个字体而已;通过 EmojiCompat ,你的设备无需等待 Android 系统更新,就可以获得最新的 Emoji 表情显示效果
EmojiCompat 的运行原理如下图所示:
从上图我们可以知道:EmojiCompat 会判断当前设备是否支持这个 Emoji,如果支持则还是使用系统内置的字体加载,如果不支持,则使用 EmojiSpan 来进行替换,从而达到替换渲染的效果
如何使用 EmojiCompat ?
要使用 EmojiCompat ,我们需要先对其进行初始化,如下:
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="" cid="n80" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">EmojiCom(config);
//EmojiCompat 的 init 方法
public static EmojiCompat init(@NonNull final Config config) {
if (sInstance == null) {
synchronized (sInstanceLock) {
if (sInstance == null) {
sInstance = new EmojiCompat(config);
}
}
}
return sInstance;
}</pre>
上述代码可以看到, EmojiCompat 是一个单例对象,初始化方法就是传入了一个 config 即配置,因此构建配置是 EmojiCompat 初始化能否成功的重点所在,Google 给我们提供了两种配置
他们分别是:
● 可下载的字体配置
● 本地捆绑的字体配置
根据 Google 官方介绍:
● 可下载的字体配置 原理:可下载的字体的方式会在首次启动 app 的时候检查本地是否有该字体,没有的话会从网上下载最新的 Emoji 字体,然后遇到不支持的 Emoji,就会从这个字体文件中,加载资源并且渲染
缺点: 可下载字体的方式,完全依赖 GMS 服务,在没有 GMS 服务的手机上并不可用
● 本地捆绑的字体配置 原理:本地捆绑的方式会在 App 打包的过程中,植入一个最新的 Emoji 字体文件,然后遇到不支持的 Emoji,就会从这个字体文件中,加载资源并且渲染
缺点: 本地捆绑的方式会嵌入一个约 9M+ 的字体文件,无形中增大了 Apk 安装包的体积
EmojiCompat 实践
因为本地捆绑字体配置的方式会使我们的 app 包体积增大 9M+,这是完全不能接受的; 而且我们的 app 主要是面向国外的用户,国外用户手机一般都有 GMS 服务,因此我选用了可下载字体配置来完成 EmojiCompat 的初始化
初始化成功后,我们就可以使用 EmojiCompat 提供的功能了,之前我们是通过如下方式进行表情包加载的:
<pre mdtype="fences" cid="n102" lang="" class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">//将当前 code 转换为 16 进制数
int hex = In("1F600", 16);
//将当前 16 进制数转换成字符数组
char[] chars = C(hex);
//将当前字符数组转换成 TextView 可加载的 String 字符串
String mEmojiString = new String(chars);</pre>
现在只需要对当前 mEmojiString 通过 EmojiCompat 处理一下即可,如下:
<pre mdtype="fences" cid="n108" lang="" class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">//判断当前 EmojiCompat 是否初始化成功
public static boolean isEmojiCompatInit(){
return EmojiCom().getLoadState() == EmojiCom;
}
//获取可兼容的 emoji 字符串
public static CharSequence getCompatEmojiString(String code) {
//将当前 code 转换为 16 进制数
int hex = In(code, 16);
//将当前 16 进制数转换成字符数组
char[] chars = C(hex);
//将当前字符数组转换成 TextView 可加载的 String 字符串
String mEmojiString = new String(chars);
//判断当前系统是否大于等于 19,并且 EmojiCompat 初始化成功
i >= Build.VERSION_CODES.KITKAT && isEmojiCompatInit()){
return EmojiCom().process(mEmojiString);
}
return mEmojiString;
}</pre>
上述代码我们使用 EmojiCompat 的 process 方法对之前的 emoji 字符串做了兼容处理,现在显示出来的表情就不会有啥问题了,这个库使用起来还是很简单的
尾述
私信发送 “底层源码” 即可免费获取 完整代码 以及 更多学习笔记 、 面试视频
技术是无止境的,你需要对自己提交的每一行代码、使用的每一个工具负责,不断挖掘其底层原理,才能使自己的技术升华到更高的层面
Android 架构师之路还很漫长,与君共勉
PS:有问题欢迎指正,可以在评论区留下你的建议和感受; 欢迎大家点赞评论,觉得内容可以的话,可以转发分享一下