本文实例讲述了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与表情图标的Map
mSmileyToRes = 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()) {
// 获取对应表情的图片id
int 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">
<LinearLayout
android:id="@+id/rl_bottom"
android:layout_width="fill_parent"
android:layout_height="50dp"
android:background="#fff"
android:gravity="center">
<Button
android: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.EmotionsEditText
android: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" />
<Button
android: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="" />
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center">
<Button
android: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="" />
<Button
android: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" />
<TextView
android: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>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
//这个就是表情包的占位空间
<FrameLayout
android: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;
}
@Override
public 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;
}
@Override
public 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() {
@Override
public void onClick(View v) {
//txtMsg.getText().append("hhh");
try {
//获取表情图片文件名
int resourceId = emojiEntity.getEmojiID();
// 在android中要显示图片信息,必须使用Bitmap位图的对象来装载
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), resourceId);
//要让图片替代指定的文字就要用ImageSpan
ImageSpan 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();
}
}
});
}
@Override
public int getItemCount() {
return mEmojiEntity.size();
}
}
}
7:最后的收到消息并解析出来:
SmileyParser.init(context);
SmileyParser smileyParser = SmileyParser.getInstance();
((TextView) viewHolder.tvContent).setText(smileyParser.addSmileySpans(msgContent));
好了,不知不觉中就完成了表情包的发送功能,其实查阅资料得知QQ微信等都是使用这种方式发送的,如果有不明白的请留言,我会继续更新的。