效果
操作演示
实际看一下效果最直观
overlook.gif
这个效果和XhsEmoticonsKeyboard的没什么区别
表情数据动态刷新
change_data.gif
这里演示了四种刷新方式
增加表情
删除表情
增加表情包
删除表情包
这里需要说明一下,什么是表情包?
表情包在代码中对应的类是EmoticonPack。一个EmoticonPack就代表了一个表情集合。比如上图中屏幕最下方的黄色微笑小图标就代表了一个表情包。
整体结构
screenshot的副本.jpg
EmoticonsBoard就是整个键盘库的核心,和表情展示相关的主要有三个部分:EmoticonsFuncView,EmoticonsIndicator和EmoticonsToolBar。
EmoticonsFuncView:展示每一页表情,继承自ViewPager
EmoticonsIndicator:表情页指示器
EmoticonsToolBar:展示表情包图标
core.jpg
这里我们只看一下表情相关的几个类,如果对其它的类有兴趣,可以下载代码自行研究。
刚才我们说了,展示表情的EmoticonsFuncView继承自ViewPager,既然是ViewPager,那么就应该有Adapter,它就是EmoticonPacksAdapter。
EmoticonPacksAdapter保存的是一个EmoticonPack列表。EmoticonPack刚才已经介绍过了,是表情包。EmoticonPack中有一个Emoticon列表。Emoticon就代表一个表情。EmoticonPack中还有一个属性:iconUri,它就是这个表情包图片的uri。每个EmoticonPack的图标最终会设置到EmoticonsToolBar里。而Emoticon列表就通过EmoticonPacksAdapter以页面的方式展示。
EmoticonsToolBar用来展示表情包图标,同时和可以在首尾增加两个View,比如增加和删除两个按钮。
类图中还有一个重要的接口:pageFactory,它的作用是生成ViewPager中每一页的View。通过它就能实现不同的页面展示。比如每页的行列数,点击表情时的效果,图标的大小等。
使用方法
Gradle
allprojects { repositories { jcenter() } }
and:
dependencies { compile 'im.ll:emoticonsboard:1.0.0' }
XML
<github.ll.emotionboard.EmoticonsBoard xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <ListView android:layout_width="match_parent" android:layout_height="match_parent"/> </LinearLayout></github.ll.emotionboard.EmoticonsBoard>
EmoticonsBoard继承自RelativeLayout,所以它里面可以包含子View,但是它的子View只能有一个,多于一个的话会报错。
上面的例子就是包含了一个LinearLayout。
设置 Adapter
Java code:
EmoticonsBoard ekBar;List<EmoticonPack> packs = new ArrayList<EmoticonPack>;// init packs...EmoticonPacksAdapter adapter = new EmoticonPacksAdapter(packs); ekBar.setAdapter(adapter);
这里很简单,重点是如何构建EmoticonPack
构建
kotlin code
fun getEmoji(context: Context): EmoticonPack<Emoticon> { val emojiArray = mutableListOf<Emoticon>() DefEmoticons.sEmojiArray.take(30).mapTo(emojiArray) { val emoticon = Emoticon() emoticon.code = it.emoji emoticon.uri = context.getResourceUri(it.icon) return@mapTo emoticon } val pack = EmoticonPack<Emoticon>() pack.emoticons = emojiArray pack.iconUri = context.getResourceUri(R.mipmap.icon_emoji) val factory = DeleteBtnPageFactory<Emoticon>() factory.deleteIconUri = context.getResourceUri(R.mipmap.icon_del) factory.line = 3 factory.row = 7 pack.pageFactory = factory return pack }
EmoticonPack有三个属性:emoticons就是表情列表。iconUri是这个表情包的图标,上面提到过。pageFactory是View工厂,上面也讲过。
这段代码首先是构造了一个Emoticon列表,Emoticon只有两个属性:code和uri。code是表情代码,uri是图片uri。
然后设置了EmoticonPack的PageFactory,在这用到的是DeleteBtnPageFactory,DeleteBtnPageFactory的功能就是能展示一个删除按钮。
EmoticonPack的创建很简单。这里有一点要注意一下,Emoticon我只提供了uri一个属性统一表示表情图片的地址。不管这个图片是资源,文件,还是网络图片,用一个uri就够了。这里的uri可以用android定义的也可以自己定义,只要能唯一确定图片的位置就行了。这里我写了一个工具类来获取各种uri:
kotlin code
enum class UriType { ASSETS, DRAWABLE, FILE, OTHER; } object UriUtils { fun getUriType(uri: String): UriType { if (uri.startsWith("android.resource:")) { return UriType.DRAWABLE } if (uri.startsWith("file:///android_asset/")) { return UriType.ASSETS } if (uri.startsWith("file://") && !uri.contains("android_asset")) { return UriType.FILE } return UriType.OTHER } fun getResourceID(context: Context, uri: String) = uri.substring("android.resource://${context.packageName}/".length) fun getFilePath(uri: String): String? { return if (getUriType(uri) != UriType.FILE) { null } else { uri.substring("file://".length) } } fun getAssetsPath(uri: String): String? { return if (getUriType(uri) != UriType.ASSETS) { null } else { uri.substring("file:///android_asset/".length)
现在主流的图片加载库,比如Glide,都可以通过uri加载图片。如果你觉得还是用资源id方便,那么你也可以自己扩展Emoticon。
那么表情图标具体是在哪个地方加载呢?没错,就是在PageFactory里。
刷新数据
kotlin code
// modify mEmojiPackmEmojiPack.isDataChanged = trueadapter?.notifyDataSetChanged()
非常简单,mEmojiPack数据改变后首先标记isDataChanged为true,然后调用notifyDataSetChanged方法就可以了。
这里注意,isDataChanged必须要设置为true
作者:Rocky1982
链接:https://www.jianshu.com/p/fd0a54b3162c