Emoji开源项目解读(一)

介绍

上一节,我们对PhotoView开源项目进行了剖析解读, 这一节呢, 我们说说Emoji表情,大家每天都在用的QQ,微信或者其他聊天工具都有这个。

在我接触到的Emoji中,大致可以分为两类:

系统支持的Emoji图标

 自定义Emoji图标

这一节我们讨论系统支持的Emoji图标,掌握了这类,自定义Emoji表情也就水到渠成了

功能特性

 常用系统Emoji图标展示

 EditorText图标展示

 TextView图标展示

 表情的删除、添加、替换

源码剖析

 代码目录结构

老规矩,先上代码结构图,有个总体的认识

样例

做一个插入表情的流程例子

  setContentView(R.layout.activity_main);
        mEditEmojicon = (EditText) findViewById(R.id.editEmojicon);
        mTxtEmojicon = (TextView) findViewById(R.id.txtEmojicon);
        mEditEmojicon.addTextChangedListener(new TextWatcherAdapter() {
            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                mTxtEmojicon.setText(s);
            }
        });

时序图

好了,上面是表情变化的一个调用流程,基本流程就是EmojiconsFragment里面的图标点击事件或者返回事件,回调一下, 让客户端来调用EmojiconEditText增删表情,然后监听EmojiconEditText的文本变化事件,来设置EmojiconTextView的文本, 这里都用到了EmojiconHandler这个类,他是表情的逻辑核心处理类,表情的管理都在这了。 我们的重点也在这了。

插入表情

我们看到在例子中是在回调方法中,调用的插入方法

    @Override
    public void onEmojiconClicked(Emojicon emojicon) {
        EmojiconsFragment.input(mEditEmojicon, emojicon);
}

然后跟进去看到

    public static void input(EditText editText, Emojicon emojicon) {
        if (editText == null || emojicon == null) {
            return;
        }

        int start = editText.getSelectionStart();
        int end = editText.getSelectionEnd();
        if (start < 0) {
            editText.append(emojicon.getEmoji());
        } else {
            editText.getText().replace(Math.min(start, end), Math.max(start, end), emojicon.getEmoji(), 0, emojicon.getEmoji().length());
        }
    }

这里看有没有选中文本或者有游标,如果没有就在后面加上表情就好了,如果有的话,就替换指定位置的文本。

删除表情

看代码

    @Override
    public void onEmojiconBackspaceClicked(View v) {
        EmojiconsFragment.backspace(mEditEmojicon);
}

进去在看

    public static void backspace(EditText editText) {
        KeyEvent event = new KeyEvent(0, 0, 0, KeyEvent.KEYCODE_DEL, 0, 0, 0, 0, KeyEvent.KEYCODE_ENDCALL);
        editText.dispatchKeyEvent(event);
}

这里直接生成了一个删除的按键实例,让EditText执行,就行了。 代码比较简洁有效,为什么这样可以呢?别急,看下面慢慢说明。

EmojiconEditText

然后,我们在来看看EmojiconEditText中,对于文字变化后的逻辑是怎么处理的?也是关键地方所在。

看代码
    @Override
    protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
        EmojiconHandler.addEmojis(getContext(), getText(), mEmojiconSize);
}

又是EmojiconHandler来做的处理,跟进去

    public static void addEmojis(Context context, Spannable text, int emojiSize) {
        int length = text.length();
        EmojiconSpan[] oldSpans = text.getSpans(0, length, EmojiconSpan.class);
        for (int i = 0; i < oldSpans.length; i++) {
            text.removeSpan(oldSpans[i]);
        }

        int skip;
        for (int i = 0; i < length; i += skip) {
//中间省略......
text.setSpan(new EmojiconSpan(context, icon, emojiSize), i, i + skip, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        }

总体思路是这样的,先删除Spannable中的样式,然后在解析表情,添加样式,在增删样式对象中我们看到了EmojiconSpan,这么个东东?它又是干啥的呢?

EmojiconSpan

可能有的童靴对样式这些比较迷糊, 好的, 为了有一个清晰的认识, 我画了一个类图,可以很明了的知道他们的关系.

看看EmojiconSpan在什么等级上面,其实和ImageSpan是一个级别的,一种样式而已,从上图也可以了解到真正的跟样式打交道的,也不是EditText而是Editable。这样设计,文本和样式是分离的,耦合度比较低,还是不错的。呵呵。

再来看看EmojiconSpan的重写方法

    public Drawable getDrawable() {
        if (mDrawable == null) {
            try {
                mDrawable = mContext.getResources().getDrawable(mResourceId);
                int size = mSize;
                mDrawable.setBounds(0, 0, size, size);
            } catch (Exception e) {
                // swallow
            }
        }
        return mDrawable;
}

那么在添加表情的时候,资源id是怎么来的呢?

大家在EmojiconHandler里面可以看到有两个属性集合,存放emoji和softbank表情的

    private static final SparseIntArray sEmojisMap = new SparseIntArray(846);
    private static final SparseIntArray sSoftbanksMap = new SparseIntArray(471);

然后在静态块中进行了初始化操作

    static {
        // People
        sEmojisMap.put(0x1f604, R.drawable.emoji_1f604);
        sEmojisMap.put(0x1f603, R.drawable.emoji_1f603);
//省略......
}

后面添加的值我们很容易理解,是资源id,前面的16进制数值Key是个什么东东呢?

这个值是随意定义的Key吗?这个还真不是,呵呵。经过查资料得知,这个还是有一套标准的。对,Emoji也是有标准的。

咱们来举个例子吧,阳光图标吧

对应代码

sEmojisMap.put(0x2600, R.drawable.emoji_2600);
sSoftbanksMap.put(0xe04a, R.drawable.emoji_2600);

大家找到对应关系了吗?对的,前面的是Symbol 标准,后面的是softbank标准,google都支持。

删除表情再议

这个在系统emoji中,程序处理比较简单,直接给EmojiconEditText一个删除的按键事件就解决了,正如上面说的那样,为什么这样做可以呢?归根到底还是因为他是系统的emoji,系统本身就可以识别这个编码,他当做一个东东来处理了,就像一个文字字符一样,如果是自定义emoji就没那么简单了,需要自己进行单独处理,下一节将会接触到这个。

好了,系统Emoji表情就说到这了,主要是EditText的操作,文本样式的应用,系统Emoji编码知识,小知识点还是蛮多的。后续大家如果还有什么问题,或者有不正确的地方, 可以提出来,共同探讨。

Github

https://github.com/rockerhieu/emojicon

Emoji图标编码

http://www.unicode.org/~scherer/emoji4unicode/snapshot/full.html

时间: 2024-08-30 12:53:09

Emoji开源项目解读(一)的相关文章

Emoji开源项目解读(二)自定义表情

介绍 上一节呢,我们解读了一个系统Emoji表情,这节呢, 我们谈谈自定义表情,如QQ.微信等,正好前两天看到一个仿QQ的一个应用,虽然还是有许多需要完善的地方, 不过对于自定义Emoji表情功能,做的也是比较成熟了,这里要谢谢白玉梁同学,下面我带领大家来一起学习一下他的这个功能实现. 根据上一节的分析呢,这节我就简要的直奔主题说了,页面布局.架构和流程都不说了. 感兴趣的可以自己看代码. 源码剖析 咱们先来看看他的assets资源文件夹 g文件夹放的是gif图,如 p文件夹放的是静态图 再来看

最新最全的 Android 开源项目合集

原文链接:https://github.com/opendigg/awesome-github-android-ui 在 Github 上做了一个很新的 Android 开发相关开源项目汇总,涉及到 Android 开发的方方面面,基本很全了.对 Android 开发感兴趣的欢迎 Star ,后续也会定期维护更新这个列表.当然,你也可以去 opendigg 上查看. -- 由欧戈分享 awesome-github-android-ui 是由OpenDigg整理并维护的安卓UI相关开源项目库集合.

自己总结的 iOS ,Mac 开源项目以及库,知识点------持续更新

自己在 git  上看到一个非常好的总结的东西,但是呢, fork  了几次,就是 fork  不到我的 git 上,干脆复制进去,但是,也是认真去每一个每一个去认真看了,并且也是补充了一些,感觉非常棒,所以好东西要分享,为啥用 CN 博客,有个好处,可以随时修改,可以持续更新,不用每次都要再发表,感觉这样棒棒的 我们 自己总结的iOS.mac开源项目及库,持续更新.... github排名 https://github.com/trending,github搜索:https://github.

前端开源项目周报0502

由OpenDigg 出品的前端开源项目周报第十九期来啦.我们的前端开源周报集合了OpenDigg一周来新收录的优质的前端开源项目,方便前端开发人员便捷的找到自己需要的项目工具等. react-sketchapp 为Sketch渲染React组件 DevExtreme 最佳响应式跨平台组件套件 bilibili-vue 全栈式开发bilibili首页 pandemonium 典型的随机相关的功能 vue-toutiao vuejs高仿今日头条移动端 MagicMusic 不一样的音乐 Vue2-M

Java开源项目(备查)

转自:http://www.blogjava.net/Carter0618/archive/2008/08/11/221222.html Spring Framework  [Java开源 J2EE框架] Spring 是一个解决了许多在J2EE开发中常见的问题的强大框架. Spring提供了管理业务对象的一致方法并且鼓励了注入对接口编程而不是对类编程的良好习惯.Spring的架构基础是基于使用JavaBean属性的 Inversion of Control容器.然而,这仅仅是完整图景中的一部分

开源项目spring-shiro-training思维导图

写在前面 终于完成了一个开源项目的思维导图解读.选spring-shiro-training这个项目解读是因为它开源,然后涉及到了很多我们常用的技术,如缓存,权限,任务调度,ssm框架,Druid监控,mybatis-plus,代码生成器等.同时也考虑到了安全方面,做了防止crsf攻击方面控制.作为一个简单易用的权限系统,它也足够我们学习了. 当然,可能解读不会很全,也可能有些写得不对.有些是基于个人的理解,一些网上参考的资料.如果想要理解一个项目单单看别人的解读是不够的,需要你去克隆下来在你的

畅谈linux开源项目openssl

OpenSSL:开源项目        三个组件:            openssl: 多用途的命令行工具:            libcrypto: 公共加密库:            libssl: 库,实现了ssl及tls: openssl命令: openssl version:程序版本号[[email protected] ~]# openssl versionOpenSSL 1.0.1e-fips 11 Feb 2013 标准命令.消息摘要命令.加密命令 标准命令:      

Github上关于iOS的各种开源项目集合(强烈建议大家收藏,查看,总有一款你需要)

下拉刷新 EGOTableViewPullRefresh - 最早的下拉刷新控件. SVPullToRefresh - 下拉刷新控件. MJRefresh - 仅需一行代码就可以为UITableView或者CollectionView加上下拉刷新或者上拉刷新功能.可以自定义上下拉刷新的文字说明.具体使用看“使用方法”. (国人写) XHRefreshControl - XHRefreshControl 是一款高扩展性.低耦合度的下拉刷新.上提加载更多的组件.(国人写) CBStoreHouseR

如何开始参与开源项目?

转载:http://linux.cn/article-4628-weixin.html#rd?sukey=cbbc36a2500a2e6c44df210b08b1326f1382f39f0316ec2175bc12c34db5cd80b3b1fe7d06dcfa42e07044652a0ba790 在过去五年我一直参与 Durgapur Linux用户组.我一直为各种开源项目进行贡献.我为开源贡献的主要原因是非常享受当你发送一个补丁或PR(pull request 提交问题)到一个开源项目的感觉