Android Emoji
对于在网络聊天中表现不好的人来说,“表情”的诞生是上帝赐予的东西。表情的话,好像可以演心情自由的年轻人。
我们现在用的很多,不管是EMOR还是图形表情包,不难发现,很多表情追求仪式感,重视意思和实时体验,大多数都是重现面部表情和肢体动作,用一种“模拟”的身体在现场。
微信表情的玫瑰花带着长长的花梗发送或接收,都像是“抓住”的代入感。拥抱是漫画形象,可以在安慰的背景下操作的表现,可以看作是发送者的手臂或接收者的双臂。这种表情弥补了网络传播中无法感知情感变化的缺陷。
解读 emoji
《Emozi》有176个符号,快乐、吐舌头、亲吻、眨眼、闭嘴等。这些符号在网络和手机上都可以看到。2014年,用统一的版本统一所有代码标准后,推出了250个新的emoji表情,使其在互联网上应用更加舒适。
2014年8月,有牛津词典,编辑了这个表情包。这意味着这些表情符号将成为正式词汇,在以后的生活和工作中广泛使用。苹果收藏了这种表情后,网络上有更多的用户使用了表情包,现在已经风靡全球。这个表情比前面提到的更广泛,很多人都在使用。
Emoji的实用性
从这种表情看非常现实的生活;例如,心情不好的时候可以做哭的表情。就像平时的心情一样,笑脸、友好也意味着礼仪,但是表情的笑脸很特别,稍微往下看就会给人一种有意义的感觉,所以特别有趣。
和女朋友或妻子说话时可能会伤透心。虽然现在证明此时此刻在想念对方,但有些网友不知道为什么这种表情没有悲心,因为比起内心,这是现在流行的手势,所以很多年轻网友在网络平台上留言,希望以后会出现这一手势,期待不久的将来会更新。
在很多表情中最受欢迎的是红心。这红色的爱情代表爱情,代表期待,也有很多人用这种表情表示感谢。(威廉莎士比亚,哈姆雷特,爱情名言)
这个表情给人的感觉是非常礼貌,情侣之间使用代表着想念,代表着浪漫。朋友之间使用代表着友情更加贴近Emoji 表情介绍
下面大概介绍一下关于 Emoji 表情:
● Emoji 是可以被插入文字中的图形符号,它是一个日本语; e 表示 "绘", moji 表示 "文字" , 连在一起就是 “绘文字”, 它最早是用于我们发短信来增强用户的一个体验,2007 年,Apple 在 iPhone 中支持了 Emoji,才让它在全球范围内流行起来
● 在 2010 年以前,Emoji 的实现是将一些特殊的符号组合替换成图片表情,例如 :) 替换成 ,这样的解决方案导致 Emoji 表情很难标准化,而且表达范围有限
● 从 2010 年开始,Unicode 开始为 Emoji 分配固定的码点,也就是说,在这之后,每一个 Unicode 字符对应一个字体,它会被渲染为图片显示
● Emoji 表情由于其表达情绪的特点,被广受欢迎。Emoji 表情的国际标准在 2015 年出台,到目前为止已经是 V13.1 版本的标准了
需求
对 Emoji 表情有了一个大概的了解之后,下面讲下产品给我提的一个需求,大概就是:从中,筛选一些常用的 Emoji 表情,然后根据 UI 设计稿,实现表情包功能即可
从上图我们可以看到:
每个表情的 Unicode 字符
● 这里解释一下 Unicode:Unicode 就是统一的字符编码标准,当需要表示一个 Unicode 字符时,通常会用 U+ 然后紧接着一个十六进制的数字来表示,如上图所列举的这些
● 每个 Unicode 字符对应的 Emoji 表情在各个平台展示的样式都不太一样,因为 Unicode 只是规定了 Emoji 的码点和含义,并没有规定它的样式,每个平台都有自己的 Emoji 实现
Emoji 表情实践
有了思路,就开始撸起柚子干,把筛选出的表情 code 放到一个集合中,然后通过 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:有问题欢迎指正,可以在评论区留下你的建议和感受; 欢迎大家点赞评论,觉得内容可以的话,可以转发分享一下