您的位置:首页 > 移动开发 > 微信开发

仿微信表情输入键盘(支持 Gif 表情图文混排 )

2017-12-11 00:00 513 查看


作者 | PandaQ404

地址 | http://www.jianshu.com/p/fddca2b0a26b
声明 | 本文是 PandaQ404 原创,已获授权发布,未经原作者允许请勿转载

简介

自定义的表情输入键盘在很多应用中都会有用到,譬如微信、QQ 等社交聊天软件中更是不可缺少的部分。本文将解析一下个人的自定义表情输入控件库 PandaEmoView 的实现和使用。

特点

支持 emoji 表情图片

支持 gif 动态表情输入显示

支持单张贴图表情(与微信收藏表情一致)

支持题图表情库的添加删除

效果图



快速使用

引入库

compile 'com.pandaq:PandaEmoView:1.0.0'


表情资源及配置文件

默认的 emoji 和 gif 表情以及他们的配置文件是放在开发包 assets 目录下的,若表情比较多比较大也可自行修改源码在 APP 启动时从服务器下载。



emoji 表情配置文件



非自定义 sticker 配置文件(自定义 sticker 是没有配置文件的)



具体使用规则

与表情输入控件相关的 EditText 必须使用 PandaEditText
PandaEditText 只是重写了 onKeyPreIme() 获取按返回键的通知,继承自 EditText 的控件可继承 PandaEditText 自定义

应用 Application 中进行全局参数配置

private void configPandaEmoView() {
new PandaEmoManager.Builder()
.with(getApplicationContext()) // 传递 Context
.configFileName("emoji.xml")// 配置文件名称
.emoticonDir("face") // asset 下存放表情的目录路径(asset——> configFileName 之间的路径,结尾不带斜杠)
.sourceDir("images") // 存放 emoji 表情资源文件夹路径(emoticonDir 图片资源之间的路径,结尾不带斜杠)
.showAddTab(true)//tab栏是否显示添加按钮
.showStickers(true)//tab栏是否显示贴图切换按键
.showSetTab(true)//tab栏是否显示设置按钮
.defaultBounds(30)//emoji 表情显示出来的宽高
.cacheSize(1024)//加载资源到内存时 LruCache 缓存大小
.defaultTabIcon(R.drawable.ic_default)//emoji表情Tab栏图标
.emojiColumn(7)//单页显示表情的列数
.emojiRow(3)//单页显示表情的行数
.stickerRow(2)//单页显示贴图表情的行数
.stickerColumn(4)//单页显示贴图表情的列数
.maxCustomStickers(30)//允许添加的收藏表情数
.imageLoader(new IImageLoader() {
@Override
public void displayImage(String path, ImageView imageView) { // 加载贴图表情的图片加载接口
Picasso.with(getApplicationContext())
.load(path)
.fit()
.centerCrop()
.into(imageView);
}
})
.build(); //构建 PandaEmoManager 单利
}


2.使用此控件的 Activity 在 manifest 文件中配置

// 这句是一定要加上的。
android:windowSoftInputMode="adjustResize"


3.使用此控件的界面 xml 文件规则

布局规则如下图,lockView 即是我们正常显示内容的 View 它与表情输入控件 PandaEmoView 属于同一层级,父布局必须为纵向线性布局,且设置 lockView 权重为 1 ,PandaEmoView 高度包裹内容即可



4.使用控件的 Activity Java 代码设置

//界面控件初始化后 .attachEditText()绑定输入控件
//初始化 KeyBoardManager,PandaEmoView.attachEditText() 必须在后调用


主要使用类及公有方法概览

PandaEmoEditText

表情输入框继承自
EditText
只对
onKeyIme()
进行复写用于监听输入键盘或者软键盘的弹出与关闭

PandaEmoView

表情输入控件 View 继承自
RelativeLayout




PandaEmoManager

PandaEmoManager
为核心配置类,表情控件的各种参数都通过此类的构造器进行配置







剩余方法都为属性值的 getter() setter() 不在赘述。

PandaEmoManager.Builder

PandaEmoManager
的构造器类,属性及方法都与 PandaEmoManager 一一对应;

KeyBoardManager

KeyBoardManager
为输入法软键盘与表情输入控件协调管理类





EmoticonManager

EmoticonManager 为 emoji 表情加载管理类,此类提供方法将资源文件根据配置文件加载进内存,方法大多数为私有方法,源码中可查看注释。

StickerManager

StickerManager 为 sticker 表情加载管理类,此类提供方法将资源文件根据配置文件加载进内存,与 EmoticonManager 类似

PandaEmoTranslator

PandaEmoTranslator 为 emoji 表情 [文字] 转表情的转换工具类





关于内存优化

因为表情,gif 表情,自定义贴图,表情包贴图这些都涉及到图片资源加载到内存中。因此开发过程中不可避免的也遇到了许多的内存优化相关的问题。

工具

就地取材,直接使用 Android Studio 的 Monitors 工具可以直观的查看到应用运行过程中内存的变化过程
优化点1 —— Gif 播放类的优化

问题:

参考网上的 gif 图文混排项目,虽然实现了 gif 与文字的图文混排效果,但存在致命的缺陷。该项目中每一个 gif 动态表情图都有一个对应的 Runable 对象去执行 gif 图片的逐帧播放,当一个表情重复输入也会有新的 Runable 对象去执行这样的操作,这样做的后果就是当输入的表情数量增加时,所消耗的内存是持续增长的。这显然不能满足生产使用的需求。

解决方案:

考虑到此处内存增加的原因是让表情动起来的 Runable 泛滥引起的,因此减少 Runable 的数量就是解决此处内存问题的关键。我的方案做的比较彻底,整个应用 gif 表情这一块儿都交给一个 Runable 去处理,这个 Runable 在 PandaTranslator 中进行图文转化时会被初始化

// PandaTranslator 的 103 - 107 行
103                   if (mGifRunnable == null) {
104                      mGifRunnable = new GifRunnable(gifDrawable, mHandler);
105                   } else {
106                      mGifRunnable.addGifDrawable(gifDrawable);
107                   }


因为 PandaTranslator 是一个单例实现,所以在他初始化后 mGifRunnable 也将保持唯一性。无论是新建初始化还是 addGifDrawable() 都是把 Gif 表情对象放入 GifRunnable 中的一个 Map 中。Map 的 key value 分别是表情控件依附的 Activity 的 LocalName 和 一个 AnimatedGifDrawable 的 List。在 GifRunnable 的 run 方法中会根据当前的
Activity 的 LocalName 去取出对应的 AnimatedGifDrawable 列表,遍历执行并按第一张 gif 表情的帧间隔去刷新 Drawable 并触发 TextView 刷新回调

@Override
public void run() {
isRunning = true;
if (currentActivity != null) {
List<AnimatedGifDrawable> runningDrawables = mGifDrawableMap.get(currentActivity);
if (runningDrawables != null) {
for (AnimatedGifDrawable gifDrawable : runningDrawables) {
AnimatedGifDrawable.RunGifCallBack listener = gifDrawable.getUpdateListener();
List<AnimatedGifDrawable.RunGifCallBack> runningListener = listenersMap.get(currentActivity);
if (runningListener != null) {
// 避免一个 TextView 多个表情时重复添加回调
if (!runningListener.contains(listener)) {
runningListener.add(listener);
}
} else {
// 为空时肯定不存在直接添加
runningListener = new ArrayList<>();
runningListener.add(listener);
listenersMap.put(currentActivity, runningListener);
}
gifDrawable.nextFrame();
}
for (AnimatedGifDrawable.RunGifCallBack callBack : listenersMap.get(currentActivity)) {
if (callBack != null) {
callBack.run();
}
}
frameDuration = runningDrawables.get(0).getFrameDuration();
}
}
mHandler.postDelayed(this, frameDuration);
}


这样就实现了全局使用一个 Runable 来执行 gif 动起来的任务,不同的界面也仅需要将该界面的 AnimatedGifDrawable 对象加入任务 Map 即可。

优化点2 —— 界面暂停或退出时 Gif 播放资源同步退出回收

上面说到的将 AnimatedGifDrawable 列表加入任务 Map,只进不出显然是不科学的也会持续增加内存的消耗。我们希望在 Activity 退出时能将将当前 Activity 的 AnimatedGifDrawable 列表销毁移除,在界面不可见但是可能会恢复时(pause 状态)暂停 Runable 的执行,减少资源消耗。于是 GifRunable 提供了如下三个方法给外部调用

/**
* 使用了表情转换的界面退出时调用,停止动态图handler
*/
public void clearHandler(String activityName) {
currentActivity = null;
//清除当前页的数据
mGifDrawableMap.remove(activityName);
// 当退出当前Activity后没表情显示时停止 Runable 清除所有动态表情数据
listenersMap.remove(activityName);
if (mGifDrawableMap.size() == 0) {
clearAll();
}
}
private void clearAll() {
mHandler.removeCallbacks(this);
mHandler.removeCallbacksAndMessages(null);
mGifDrawableMap.clear();
isRunning = false;
}
/**
* 启动运行
*/
public void startHandler(String activityName) {
currentActivity = activityName;
if (mGifDrawableMap != null && mGifDrawableMap.size() > 0 && !isRunning) {
run();
}
}


它的调用入口都在 PandaTranslator 中,然后我们只需在使用到 PandaEmoView 或者直接在 BaseActivity 的 onResume(),onPause(),onDestory() 中分别调用以下三个方法:

PandaTranslator.getInstance().resumeGif(activityLocalName);
PandaTranslator.getInstance().pauseGif();
PandaTranslator.getInstance().clearGif(activityLocalName)


优化点3 —— 使用 LruCache 缓存 emoji 资源

根据 LRU 规则将表情 Gif 缓存,避免重复加载创建新对象。
最后

因为离职从南京回到成都还有工作的各种各样的原因,也是有四个多月没更博客了。这是重新开始写博客的第一篇,之后大概会以一个月 2-3 篇的样子更新,记录与分享,欢迎大家关注我的简书。
本库地址 https://github.com/PandaQAQ/PandaEmoView 欢迎 star 和提 issue




开源库

推荐几个开源库

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: