Android编程实现QQ表情的发送和接收完整实例(附源码)

本文实例讲述了Android编程实现QQ表情的发送和接收。分享给大家供大家参考,具体如下:

在自己做一个聊天应用练习的时候,需要用到表情,于是就想着模仿一下QQ表情,图片资源完全copy的QQ.apk,解压就可以得到,这里不细说。

下面将该应用中的表情模块功能抽离出来,以便自己以后复习回顾。。

先看一下效果图:

首先进入界面:(完全仿照QQ)

点击一下上面的表情图标:

选择一些表情,输入一些文字混合:

点击发送:

可以看到文字和表情图片都一起显示出来了。

下面列出一些关键代码:

表情工具类ExpressionUtil:

public class ExpressionUtil {
 /**
  * 对spanableString进行正则判断,如果符合要求,则以表情图片代替
  * @param context
  * @param spannableString
  * @param patten
  * @param start
  * @throws SecurityException
  * @throws NoSuchFieldException
  * @throws NumberFormatException
  * @throws IllegalArgumentException
  * @throws IllegalAccessException
  */
 public static void dealExpression(Context context,SpannableString spannableString, Pattern patten, int start) throws SecurityException, NoSuchFieldException, NumberFormatException, IllegalArgumentException, IllegalAccessException {
  Matcher matcher = patten.matcher(spannableString);
  while (matcher.find()) {
   String key = matcher.group();
   if (matcher.start() < start) {
    continue;
   }
   Field field = R.drawable.class.getDeclaredField(key);
   int resId = Integer.parseInt(field.get(null).toString()); //通过上面匹配得到的字符串来生成图片资源id
   if (resId != 0) {
    Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resId);
    ImageSpan imageSpan = new ImageSpan(bitmap); //通过图片资源id来得到bitmap,用一个ImageSpan来包装
    int end = matcher.start() + key.length(); //计算该图片名字的长度,也就是要替换的字符串的长度
    spannableString.setSpan(imageSpan, matcher.start(), end, Spannable.SPAN_INCLUSIVE_EXCLUSIVE); //将该图片替换字符串中规定的位置中
    if (end < spannableString.length()) { //如果整个字符串还未验证完,则继续。。
     dealExpression(context,spannableString, patten, end);
    }
    break;
   }
  }
 }
 /**
  * 得到一个SpanableString对象,通过传入的字符串,并进行正则判断
  * @param context
  * @param str
  * @return
  */
 public static SpannableString getExpressionString(Context context,String str,String zhengze){
  SpannableString spannableString = new SpannableString(str);
  Pattern sinaPatten = Pattern.compile(zhengze, Pattern.CASE_INSENSITIVE);  //通过传入的正则表达式来生成一个pattern
  try {
   dealExpression(context,spannableString, sinaPatten, 0);
  } catch (Exception e) {
   Log.e("dealExpression", e.getMessage());
  }
  return spannableString;
 }
}

在显示聊天页面的list的适配器中,我们需要做如下的显示,即调用上面工具类的方法:

SimpleChatAdapter中的内部类ViewHolder:

private class ViewHolder{
  RelativeLayout chat_layout;
  ImageView image;
  TextView text;
  public ViewHolder(View convertView){
   chat_layout=(RelativeLayout) convertView.findViewById(R.id.team_singlechat_id_listiteam);
   image=(ImageView) convertView.findViewById(R.id.team_singlechat_id_listiteam_headicon);
   text=(TextView) convertView.findViewById(R.id.team_singlechat_id_listiteam_message);
  }
  public void setData(MessageInfo msg){
   RelativeLayout.LayoutParams rl_chat_left=((RelativeLayout.LayoutParams)chat_layout.getLayoutParams());
   RelativeLayout.LayoutParams rl_tv_msg_left=((RelativeLayout.LayoutParams)text.getLayoutParams());
   RelativeLayout.LayoutParams rl_iv_headicon_left=((RelativeLayout.LayoutParams)image.getLayoutParams());
   if(!DicqConstant.DEFAULTMAC.equalsIgnoreCase(msg.getUsermac())){ //根据本地的mac地址来判断该条信息是属于本人所说还是对方所说
   //如果是自己说的,则显示在右边;如果是对方所说,则显示在左边
    rl_chat_left.addRule(RelativeLayout.ALIGN_PARENT_LEFT,-1);
    rl_chat_left.addRule(RelativeLayout.ALIGN_PARENT_RIGHT,0);
    rl_iv_headicon_left.addRule(RelativeLayout.ALIGN_PARENT_LEFT,-1);
    rl_iv_headicon_left.addRule(RelativeLayout.ALIGN_PARENT_RIGHT,0);
    rl_tv_msg_left.addRule(RelativeLayout.RIGHT_OF,R.id.team_singlechat_id_listiteam_headicon);
    rl_tv_msg_left.addRule(RelativeLayout.LEFT_OF,0);
    text.setBackgroundResource(R.drawable.balloon_l_selector);
   }else{
    rl_chat_left.addRule(RelativeLayout.ALIGN_PARENT_LEFT,0);
    rl_chat_left.addRule(RelativeLayout.ALIGN_PARENT_RIGHT,-1);
    rl_iv_headicon_left.addRule(RelativeLayout.ALIGN_PARENT_LEFT,0);
    rl_iv_headicon_left.addRule(RelativeLayout.ALIGN_PARENT_RIGHT,-1);
    rl_tv_msg_left.addRule(RelativeLayout.RIGHT_OF,0);
    rl_tv_msg_left.addRule(RelativeLayout.LEFT_OF,R.id.team_singlechat_id_listiteam_headicon);
    text.setBackgroundResource(R.drawable.balloon_r_selector);
   }
   image.setImageResource(PrortaitUtils.conversionIdToRes(msg.getProtrait()));  //设置头像
   String str = msg.getMsg(); //消息具体内容
   String zhengze = "f0[0-9]{2}|f10[0-7]"; //正则表达式,用来判断消息内是否有表情
   try {
    SpannableString spannableString = ExpressionUtil.getExpressionString(context, str, zhengze);
    text.setText(spannableString);
   } catch (NumberFormatException e) {
    e.printStackTrace();
   } catch (SecurityException e) {
    e.printStackTrace();
   } catch (IllegalArgumentException e) {
    e.printStackTrace();
   }
  }
}

关于表情弹出框的实现如下:

MainActivity:

/**
* 创建一个表情选择对话框
*/
private void createExpressionDialog() {
  builder = new Dialog(MainActivity.this);
  GridView gridView = createGridView();
  builder.setContentView(gridView);
  builder.setTitle("默认表情");
  builder.show();
  gridView.setOnItemClickListener(new OnItemClickListener() {
   @Override
   public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
     long arg3) {
    Bitmap bitmap = null;
    bitmap = BitmapFactory.decodeResource(getResources(), imageIds[arg2 % imageIds.length]);
    ImageSpan imageSpan = new ImageSpan(MainActivity.this, bitmap);
    String str = null;
    if(arg2<10){
     str = "f00"+arg2;
    }else if(arg2<100){
     str = "f0"+arg2;
    }else{
     str = "f"+arg2;
    }
    SpannableString spannableString = new SpannableString(str);
    spannableString.setSpan(imageSpan, 0, 4, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
    edit.append(spannableString);
    builder.dismiss();
   }
  });
}
/**
* 生成一个表情对话框中的gridview
* @return
*/
private GridView createGridView() {
  final GridView view = new GridView(this);
  List<Map<String,Object>> listItems = new ArrayList<Map<String,Object>>();
  //生成107个表情的id,封装
  for(int i = 0; i < 107; i++){
   try {
    if(i<10){
     Field field = R.drawable.class.getDeclaredField("f00" + i);
     int resourceId = Integer.parseInt(field.get(null).toString());
     imageIds[i] = resourceId;
    }else if(i<100){
     Field field = R.drawable.class.getDeclaredField("f0" + i);
     int resourceId = Integer.parseInt(field.get(null).toString());
     imageIds[i] = resourceId;
    }else{
     Field field = R.drawable.class.getDeclaredField("f" + i);
     int resourceId = Integer.parseInt(field.get(null).toString());
     imageIds[i] = resourceId;
    }
   } catch (NumberFormatException e) {
    e.printStackTrace();
   } catch (SecurityException e) {
    e.printStackTrace();
   } catch (IllegalArgumentException e) {
    e.printStackTrace();
   } catch (NoSuchFieldException e) {
    e.printStackTrace();
   } catch (IllegalAccessException e) {
    e.printStackTrace();
   }
   Map<String,Object> listItem = new HashMap<String,Object>();
   listItem.put("image", imageIds[i]);
   listItems.add(listItem);
  }
  SimpleAdapter simpleAdapter = new SimpleAdapter(this, listItems, R.layout.team_layout_single_expression_cell, new String[]{"image"}, new int[]{R.id.image});
  view.setAdapter(simpleAdapter);
  view.setNumColumns(6);
  view.setBackgroundColor(Color.rgb(214, 211, 214));
  view.setHorizontalSpacing(1);
  view.setVerticalSpacing(1);
  view.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.WRAP_CONTENT));
  view.setGravity(Gravity.CENTER);
  return view;
}

完整实例代码代码点击此处本站下载。

希望本文所述对大家Android程序设计有所帮助。

(0)

相关推荐

  • Android输入框添加emoje表情图标的实现代码

    前言 再次写聊天的时候才发现,代码积累是一件非常重要的事情,就如这篇博客的意图其实就是代码积累的目的,其实没什么难度,但是一件很琐碎的事情真的也需要时间去完成和调试,所以,获取你在写一个功能的时候会觉得并没有多难,但是如果可以最好把代码整理/积累下来. demo描述 demo的功能其实就是仿照微信的 聊天 emoje 选择,采用了 viewpager+gridView 的方案,不过有空我会补上 recyclerView 的方案,目前还是先把功能实现了再说.另外在 TextView 和 EditT

  • android高仿微信表情输入与键盘输入代码(详细实现分析)

    表情与键盘的切换输入大部分IM都会需要到,之前自己实现了一个,还是存在些缺陷,比如说键盘与表情切换时出现跳闪问题,这个困扰了我些时间,不过所幸在Github(其代码整体结构很不错)并且在论坛上找些解决思路,再加上研究了好几个开源项目的代码,最后终于苦逼地整合出比较不错的实现效果(这里不仅给出了实现方案,还提供一个可拓展的fragment模板以便大家实现自己的表情包)代码我已进行另外的封装与拓展,大家需要其他表情的话只需要根据fragment模板实现自己的表情界面,然后根据工厂类获取即可,实现效果

  • Android输入法与表情面板切换时的界面抖动问题解决方法

    昨天琢磨了下Android的输入法弹出模式,突然发现利用动态切换输入法的弹出模式可以解决输入法抖动的问题.具体是怎样的抖动呢?我们先看微博的反面教材. [具体表现为:表情面板与输入法面板高度不一致,从而导致弹出输入法(layout被挤压)时,同时又需要隐藏表情面板(layout被拉升),最终让界面产生了高度差抖动,所以在切换时明显会有不大好的抖动体验)] 使用了解决抖动的解决方案后,效果如下: [这样的方案明显比微博的切换更平滑] 老样子,先说思路.主要我们要用到两个输入法弹出模式,分别是:ad

  • 完整的Android表情功能处理方案

    Android表情功能处理方案概述 1.原理和实现思路 2.表情图片显示 3.表情面板 4.表情的输入框插入和删除 5.表情添加脚本 Android中表情功能,一般都不是用ImageView去设置图片实现的,表情一般会嵌套在文本之中,那么如何实现呢,这里就介绍一下其中的原理,此外还有相关功能的实现思路和具体代码. 先看下良心动态图 1.原理和思路 a.表情内容的数据格式 表情看上去是图片,但是在数据传输的时候本质上是一个特殊文本: 比如QQ表情就是一个 "/表情字母"的结构,比如害羞的

  • Android高仿微信表情输入与键盘输入详解

    最近公司在项目上要使用到表情与键盘的切换输入,自己实现了一个,还是存在些缺陷,比如说键盘与表情切换时出现跳闪问题,这个相当困扰我,不过所幸在Github(其中一个不错的开源项目,其代码整体结构很不错)并且在论坛上找些解决方案,再加上我也是研究了好多个开源项目的代码,最后才苦逼地整合出比较不错的实现效果,可以说跟微信基本一样(嘿嘿,只能说目前还没发现大Bug,若发现大家一起日后慢慢完善,这里我也只是给出了实现方案,拓展其他表情我并没有实现哈,不过代码中我实现了一个可拓展的fragment模板以便大

  • Android开发技巧之像QQ一样输入文字和表情图像

    EditText和TextView一样,也可以进行图文混排.所不同的是,TextView只用于显示图文混排效果,而EditText不仅可显示,也可混合输入文字和图像,让我们先回顾一下图5.2所示的QQ聊天输入框,在输入框中可以同时输入文字和表情图像.实际上,这种效果在Android SDK中只需要几行代码就可以实现.为了使读者更有学习的冲动,先来欣赏一下即将实现的效果,如图5.16所示. 图5.16 在EditText控件中输入文字和图像 为了实现这个程序,首先来准备一些要用到的素材,也就是要在

  • Android编程开发实现TextView显示表情图像和文字的方法

    本文实例讲述了Android编程开发实现TextView显示表情图像和文字的方法.分享给大家供大家参考,具体如下: 从这个案例中我们可以学到当我们美化图片美化界面的时候可以在某一区域输入图片和文字混搭信息,第三张图片按比例缩小,第四张图像有超链接 布局文件 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.andro

  • Android自带emoji表情的使用方法详解

    什么是emoji表情 emoji表情是一种表情符号,在代码中它现在其实是一组遵循Unicode的编码,即每一个表情符号都对应了一个Unicode编码.更进一步说,emoji表情实际上是一组Unicode编码与一组表情描述之间的对应.注意,这里所说的不是表情图片,而是表情描述.那么图片的实现是由谁来负责的呢?图片是由各个系统或者软件针对统一的表情描述来各自实现的,他们都遵循统一的Unicode编码规范.也就是说Unicode编码其所对应的表情描述是统一的,是所有人都要共同遵守的一套标准或者规范,而

  • Android编程开发之EditText实现输入QQ表情图像的方法

    本文实例讲述了Android编程开发之EditText实现输入QQ表情图像的方法.分享给大家供大家参考,具体如下: 实现效果如下: 将QQ表情图像放到res下的drawable-hdpi文件夹下: 布局文件: <EditText android:id="@+id/edittext" android:layout_width="fill_parent" android:layout_height="wrap_content" android:

  • 基于Android开发支持表情的实现详解

    最近项目需要支持表情,表情的添加和解析实现基本上是参照Android自身的SmileyParser,具体就不多讲了,直接贴上代码: 复制代码 代码如下: public class SmileyParser {private static SmileyParser sInstance = null; private Context mContext = null;private Pattern mPattern = null;private HashMap<String, Integer> mS

随机推荐