本文实例讲述了Android编程开发实现输入(自定义表情包)QQ表情图像并发送出去别人收到并解析出来的方法。分享给大家供大家参考,原来QQ微信等发送表情其实发送的都不是表情,而是一个富文本,收到消息后再解析得来的,具体效果如下

表情发送出去是这样:

最近在开发的一个项目是即时通讯项目,像QQ,微信等功能的项目,其中我负责的一个模块中含有表情发送的

功能,具体需求如下:

1:自定义我们自己的表情包

2:在输入框旁边点击头像按钮像QQ微信一样跳出很多表情供我们选择

3:点击表情在输入框中显示,可以和文字混合排列。

*************************************************这是个分界线***************************************************************

4:点击发送通过服务器发出去

5:对方收到文字和表情的信息(注意这里是表情而不是一个符号或者文字),并且可以正常交流。

***********************************************这又是一个分界线************************************************************

6:在输入表情的时候会出现在文字中间插入表情的时候就会插入到最后,但是已经解决了。

下面开始我的开发步骤:

因为之前没有遇到这样的问题,网上也比较少的讲述,也是查阅了很久结合自己的感悟,其中上面的分界线是卡着

我两天的地方,所以做一个分界线,纪念一下,好了开始正题:

1:首先找到表情图片的资源,图片截图如下:

2:如果有需要的话我放个链接:自定义表情QQ微信等表情包。

3:为了简单起见我只选择了7张图片分别定义为f001-f007为图片名,放到不同的分辨率的文件夹下面,这步相信大家都会。

4:在values文件夹下面的arrays.xml中定义如下格式(当然根据我们自己的定义,这个定义是和文字一起传输代替表情的符号):

<?xml version="1.0" encoding="UTF-8"?>
<resources><!--表情的自定义格式--><string-array name="default_smiley_texts"><item>"[emoticon1]"</item><item>"[emoticon2]"</item><item>"[emoticon3]"</item><item>"[emoticon4]"</item><item>"[emoticon5]"</item><item>"[emoticon6]"</item><item>"[emoticon7]"</item></string-array>
</resources>

5:构建一个工具类来解析我们的表情包,这里我取名为SmileyParser.java文件放在我们的工具文件夹下面如下:

package com.im.rainbowchat.logic.chat_friend.utils;import android.content.Context;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.style.ImageSpan;import com.im.R;import java.util.HashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;/*** 表情解析工具类* 解析Text中的表情图片* Created by AndyYuan on 2018/10/27.*/public class SmileyParser {/*** 单例模式 1文字资源,图片资源 2.使用正则表达式进行匹配文字 3.把edittext当中整体的内容匹配正则表达式一次* 4.SpannableStringBuilder 进行替换*/private static SmileyParser sInstance;public static SmileyParser getInstance() {return sInstance;}public static void init(Context context) {sInstance = new SmileyParser(context);}private final Context mContext;private final String[] arrText;// 正则表达式private final Pattern mPattern;// String 图片字符串 Integer表情private final HashMap<String, Integer> mSmileyToRes;// arrays里面的表情内容public static final int DEFAULT_SMILEY_TEXTS = R.array.default_smiley_texts;private SmileyParser(Context context) {mContext = context;// 获取表情文字资源arrText = mContext.getResources().getStringArray(DEFAULT_SMILEY_TEXTS);// 获取表情ID与表情图标的MapmSmileyToRes = buildSmileyToRes();// 获取构建的正则表达式mPattern = buildPattern();}// 表情图片集合private static final int[] DEFAULT_SMILEY_RES_IDS = {R.drawable.f001, R.drawable.f002,R.drawable.f003, R.drawable.f004, R.drawable.f005,R.drawable.f006, R.drawable.f007};/*** 使用HashMap的key-value的形式来影射表情的ID和图片资源** @return*/private HashMap<String, Integer> buildSmileyToRes() {if (DEFAULT_SMILEY_RES_IDS.length != arrText.length) {throw new IllegalStateException("ID和图片不匹配");}HashMap<String, Integer> smileyToRes = new HashMap<String, Integer>(arrText.length);for (int i = 0; i < arrText.length; i++) {// 图片名称作为key值,图片资源ID作为value值smileyToRes.put(arrText[i], DEFAULT_SMILEY_RES_IDS[i]);}return smileyToRes;}/*** 构建正则表达式,用来找到我们所要使用的图片** @return*/private Pattern buildPattern() {StringBuilder patternString = new StringBuilder(arrText.length * 3);patternString.append('(');for (String s : arrText) {patternString.append(Pattern.quote(s));patternString.append('|');}patternString.replace(patternString.length() - 1,patternString.length(), ")");// 把String字符串编译成正则表达式()// ([调皮]|[调皮]|[调皮])return Pattern.compile(patternString.toString());}/*** 根据文本替换成图片** @param text 对应表情* @return 一个表示图片的序列*/public CharSequence addSmileySpans(CharSequence text) {// 把文字替换为对应图片SpannableStringBuilder builder = new SpannableStringBuilder(text);// 判断提取工具类(按照正则表达式)Matcher matcher = mPattern.matcher(text);while (matcher.find()) {// 获取对应表情的图片idint resId = mSmileyToRes.get(matcher.group());// 替换制定字符builder.setSpan(new ImageSpan(mContext, resId), matcher.start(),matcher.end(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);}return builder;}}

6.基本工作就做到这里,下面开始我们的关键的两步:

(一):显示的地方,我们在自定义的输入框(就是上面的发送文字表情的自定义的输入框)下面留一定的占位空间其中XML文件如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="fill_parent"android:layout_height="wrap_content"android:orientation="vertical"><LinearLayoutandroid:id="@+id/rl_bottom"android:layout_width="fill_parent"android:layout_height="50dp"android:background="#fff"android:gravity="center"><Buttonandroid:id="@+id/multi_chatting_list_view_sendVoiceBtn"android:layout_width="35dp"android:layout_height="35dp"android:layout_marginLeft="5dp"android:background="@drawable/chat_realvoice_btn"android:text="" /><com.im.rainbowchat.logic.chat_friend.EmotionsEditTextandroid:id="@+id/multi_chatting_list_view_msgEdit"android:layout_width="0dip"android:layout_height="33dp"android:layout_marginLeft="5dp"android:layout_marginRight="5dp"android:layout_weight="1"android:background="@drawable/chat_put_in"android:focusable="true"android:hint="@string/chat_message_input_hint"android:imeOptions="actionSearch"android:inputType="text"android:paddingLeft="7dp"android:singleLine="true"android:textColor="@color/black"android:textSize="16sp" /><Buttonandroid:id="@+id/multi_chatting_list_view_sendImgBtn"android:layout_width="35dp"android:layout_height="35dp"android:layout_marginLeft="5dp"android:layout_marginRight="5dp"android:background="@drawable/chat_plus_emoji"android:text="" /><FrameLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:gravity="center"><Buttonandroid:id="@+id/multi_chatting_list_view_plusBtn"android:layout_width="35dp"android:layout_height="35dp"android:layout_marginLeft="0dp"android:layout_marginRight="5dp"android:background="@drawable/chat_plus_btn"android:text="" /><Buttonandroid:id="@+id/multi_chatting_list_view_sendBtn"android:layout_width="38dp"android:layout_height="33dp"android:layout_marginLeft="0dp"android:layout_marginRight="5dp"android:background="@drawable/chat_send_btn"android:text="@string/chat_send_message"android:textColor="@color/white"android:textSize="13sp"android:visibility="gone" /><TextViewandroid:id="@+id/multi_chatting_list_view_prohibitText"style="@style/text_witheShadow2"android:layout_width="38dp"android:layout_height="35dp"android:layout_marginRight="5dp"android:background="@drawable/bbs_chatting_prohibit_speech_checker_bgimg"android:clickable="true"android:gravity="center"android:text="--"android:textColor="@color/red_for_text"android:textSize="18sp"android:visibility="gone" /></FrameLayout></LinearLayout><FrameLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content">
//这个就是表情包的占位空间<FrameLayoutandroid:id="@+id/multi_chatting_recycler_view_bottomContentFL"android:layout_width="fill_parent"android:layout_height="190dp"android:background="@drawable/chat_plus_functions_layout_bg"android:gravity="center"android:orientation="vertical"android:paddingLeft="20dp"android:paddingRight="20dp"android:paddingTop="15dp"android:visibility="gone"></FrameLayout></FrameLayout></LinearLayout>

(二):在代码中初始化我们的表情

abstract class GroupChattingEmojiUIWrapper {protected Activity parentActivity = null;/*** 主Activity的layout预留给本布局的父布局*/protected FrameLayout layoutbottomContentOfParent = null;private List<EmojiEntity> emojiEntityList = new ArrayList<>();/*** recyclerView 布局对象*/private RecyclerView emojiRecyclerView = null;public GroupChattingEmojiUIWrapper(final Activity context, final FrameLayout layoutbottomContent) {this.parentActivity = context;this.layoutbottomContentOfParent = layoutbottomContent;EmojiUtil.initEmojis(emojiEntityList);this.emojiRecyclerView = new RecyclerView(context);StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(8, StaggeredGridLayoutManager.VERTICAL);emojiRecyclerView.setLayoutManager(layoutManager);EmojiAdapter emojiAdapter = new EmojiAdapter(emojiEntityList);emojiRecyclerView.setAdapter(emojiAdapter);// 将更多功能的recyclerview加入到输入框下方的更多功能父布局中this.layoutbottomContentOfParent.addView(this.emojiRecyclerView, new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT));}public void auto() {if (this.isShowing()) {this.hide();} else {this.show();}}public void show() {this.layoutbottomContentOfParent.setVisibility(View.VISIBLE);}public void hide() {this.layoutbottomContentOfParent.setVisibility(View.GONE);}public boolean isShowing() {return (this.layoutbottomContentOfParent.getVisibility() == View.VISIBLE);}class EmojiAdapter extends RecyclerView.Adapter<EmojiAdapter.ViewHolder> {private List<EmojiEntity> mEmojiEntity;class ViewHolder extends RecyclerView.ViewHolder {ImageView emojiIV;public ViewHolder(View view) {super(view);emojiIV = view.findViewById(R.id.chatting_plus_functions_gridview_item_imageView);}}public EmojiAdapter(List<EmojiEntity> emojiEntities) {mEmojiEntity = emojiEntities;}@Overridepublic EmojiAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.chatting_plus_emoji_gridview_item, parent, false);EmojiAdapter.ViewHolder holder = new EmojiAdapter.ViewHolder(view);return holder;}@Overridepublic void onBindViewHolder(EmojiAdapter.ViewHolder holder, final int position) {final EmojiEntity emojiEntity = mEmojiEntity.get(position);holder.emojiIV.setImageResource(emojiEntity.getEmojiID());holder.emojiIV.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {//txtMsg.getText().append("hhh");try {//获取表情图片文件名int resourceId = emojiEntity.getEmojiID();// 在android中要显示图片信息,必须使用Bitmap位图的对象来装载Bitmap bitmap = BitmapFactory.decodeResource(getResources(), resourceId);//要让图片替代指定的文字就要用ImageSpanImageSpan imageSpan = new ImageSpan(AlarmsActivity.this, bitmap);SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(emojiEntity.getName());//图片的前缀名spannableStringBuilder.setSpan(imageSpan, 0, 11, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);//在此地方做一个判断,如果光标是在最后就直接append添加到最后就可以了if(txtMsg.getSelectionStart()==txtMsg.getText().length()){txtMsg.append(spannableStringBuilder);}else{//如果光标在中间就把这个富文本添加到字体行间,从而解决不能在文本中插入表情的问题int index=txtMsg.getSelectionStart();Editable editable=txtMsg.getText();editable.insert(index,spannableStringBuilder);}} catch (Exception e) {e.printStackTrace();}}});}@Overridepublic int getItemCount() {return mEmojiEntity.size();}}
}

7:最后的收到消息并解析出来:

SmileyParser.init(context);
SmileyParser smileyParser = SmileyParser.getInstance();
((TextView) viewHolder.tvContent).setText(smileyParser.addSmileySpans(msgContent));

好了,不知不觉中就完成了表情包的发送功能,其实查阅资料得知QQ微信等都是使用这种方式发送的,如果有不明白的请留言,我会继续更新的。

Android开发中自定义表情并发送出去之经典的发送表情相关推荐

  1. android自定义progressbar样式,Android开发中如何实现自定义ProgressBar的样式

    Android开发中如何实现自定义ProgressBar的样式 发布时间:2020-11-20 16:08:10 来源:亿速云 阅读:294 作者:Leah Android开发中如何实现自定义Prog ...

  2. android 自定义刷新控件,Android开发中MJRefresh自定义刷新动画效果

    有时候我们对自己开发的项目经常不满意,但是我们要达到自定义刷新动画的效果有一定的难度,别着急,下面爱站技术频道和大家分享Android开发中MJRefresh自定义刷新动画效果,一起来学习吧! [一] ...

  3. Android底部日期控件,Android开发中实现IOS风格底部选择器(支持时间 日期 自定义)...

    本文Github代码链接 先上图吧: 这是笔者最近一个项目一直再用的一个选择器库,自己也在其中做了修改,并决定持续维护下去. 先看使用方法: 日期选择: private void showDateDi ...

  4. Android开发中使用七牛云存储进行图片上传下载

    Android开发中的图片存储本来就是比较耗时耗地的事情,而使用第三方的七牛云,便可以很好的解决这些后顾之忧,最近我也是在学习七牛的SDK,将使用过程在这记录下来,方便以后使用. 先说一下七牛云的存储 ...

  5. Android开发中常见的设计模式

    对于开发人员来说,设计模式有时候就是一道坎,但是设计模式又非常有用,过了这道坎,它可以让你水平提高一个档次.而在android开发中,必要的了解一些设计模式又是非常有必要的.对于想系统的学习设计模式的 ...

  6. android listview下拉动画效果,Android开发中利用ListView实现一个渐变式的下拉刷新动画...

    Android开发中利用ListView实现一个渐变式的下拉刷新动画 发布时间:2020-11-23 16:50:31 来源:亿速云 阅读:80 作者:Leah 本篇文章给大家分享的是有关Androi ...

  7. android中资源文件的两种访问方式,在android开发中进行数据存储与访问的多种方式介绍...

    在android开发中进行数据存储与访问的多种方式介绍 更新时间:2013年06月07日 16:24:23   作者: 很多时候我们的软件需要对处理后的数据进行存储或再次访问,Android为数据存储 ...

  8. android开发中遇到的问题汇总

    android开发中遇到的问题汇总(五),android汇总127.ANDROID仿IOS时间_ANDROID仿IOS弹出提示框 http://dwtedx.com/itshare_297.html1 ...

  9. 浅谈Android开发中的NFC功能

    目录 1."NFC"的自我描述 1.1 NFC功能的基本概念 1.2 NFC功能的背景.特性及发展趋势 2.NFC的基础知识.基本原理 2.1 NFC的工作模式 2.2 实现NFC ...

  10. Android开发中的一些小知识点记录(101-120)

    编写不易,如有转载,请声明出处:http://blog.csdn.net/zxc514257857/article/details/118554522 Android开发中的一些小知识点记录(1-20 ...

最新文章

  1. (1)学习数组,集合,IEnumerable接口,引申学习迭代器
  2. 笔记 | 深入理解深度学习语义分割
  3. 中科大团队打造“象鼻”机器人,开门、擦玻璃、会给女朋友拧瓶盖的那种
  4. vector模板,初学者必读
  5. ACM-ICPC 2018 沈阳赛区网络预赛 D Made In Heaven(第k短路,A*算法)
  6. java类的定义的实例_Java中类的定义和初始化示例详解
  7. python数据分析函数大全_python中数据分析常用函数整理
  8. html52D转换3D,CSS3 Transform 2D和3D转换
  9. 4.6上午口语练习 阅读词汇
  10. 【Elasticsearch】Elasticsearch 存储桶聚合
  11. 使用 MIDP 底层用户接口 API
  12. python 分布式存储_Amazon S3 分布式存储的 python 接口实现
  13. 归档日志存在arch_还在用ELK? 是时候了解一下轻量化日志服务Loki了
  14. Novernber Rain
  15. centos7.2 部署k8s集群
  16. eclipse基础实用教程
  17. 广告牌定时器怎么设置时间_定时器怎么调时间
  18. 战地1服务器怎么显示fps,《战地1》显示FPS帧数方法介绍 怎么显示FPS帧数
  19. 2023联发科实习春招秋招内推内推码面经总结
  20. 在线登录注册功能(android客户端+javaweb服务端+腾讯云服务器+腾讯云数据库)

热门文章

  1. 看完《一九四二》的感受--也写给正在找工作时迷茫的你
  2. JS数据结构中的集合结构详解
  3. IBM服务器无法启动怎么恢复
  4. Android自定义华为睡眠,Android自定义View
  5. PHP自学笔记 ---李炎恢老师PHP第一季 TestGuest0.4
  6. Vue3-歌词根据时间自动滚动
  7. 云南企业私有云平台搭建解决方案、Zstack云平台管理软件介绍
  8. 网站备案 服务器变更,网站变更服务器备案
  9. 我学炒外汇 第二十二篇实战心得
  10. 【原创】QT5-卸载精灵v1.0-卸载windows软件-简易版