zl程序教程

您现在的位置是:首页 >  移动开发

当前栏目

仿微信聊天表情发送详解手机开发

手机开发 详解 发送 聊天 表情 仿微信
2023-06-13 09:20:13 时间

如题,这是公司项目的一个功能模块,先上个效果图:

仿微信聊天表情发送详解手机开发

其次大致说说原理:

1,首先判断输入的字符,是否包含表情的文字,比如  仿微信聊天表情发送详解手机开发 这个表情对应的文件名为 emoji_1.png,它对应的文字描述 : 可爱,如果我们在输出的是输出这么一句话:老婆,我想你了仿微信聊天表情发送详解手机开发。  那么我们对应的根本文字就是:老婆,我想你了可爱

2,具体的转换过程就是用正则表达式比配文字中是否含有[xxx]这类的文字,如果有,那么我们就根据拿到的[xxx]找到它对应的资源文件id,当然这其中有一个关系表,看你怎么处理这个关系了。最后将其用SpannableString替换成文字,表面上显示有图片,其实TextView里的text依然是:老婆,我想你了可爱。这个过程明白么?

下面贴上DEMO工程的结构:

仿微信聊天表情发送详解手机开发

再贴上几个重要的类:


[java]
view plain
copy
print
? package com.example.facedemo;    import java.util.ArrayList;  import java.util.HashMap;  import java.util.List;  import java.util.regex.Matcher;  import java.util.regex.Pattern;    import android.content.Context;  import android.graphics.Bitmap;  import android.graphics.BitmapFactory;  import android.text.Spannable;  import android.text.SpannableString;  import android.text.TextUtils;  import android.text.style.ImageSpan;  import android.util.Log;    /**   *   ******************************************   * @author 廖乃波   * @文件名称 : FaceConversionUtil.java   * @创建时间 : 2013-1-27 下午02:34:09   * @文件描述 : 表情轉換工具   ******************************************   */  public class FaceConversionUtil {     /** 每一页表情的个数 */   private int pageSize = 20;     private static FaceConversionUtil mFaceConversionUtil;     /** 保存于内存中的表情HashMap */   private HashMap String, String  emojiMap = new HashMap String, String      /** 保存于内存中的表情集合 */   private List ChatEmoji  emojis = new ArrayList ChatEmoji      /** 表情分页的结果集合 */   public List List ChatEmoji  emojiLists = new ArrayList List ChatEmoji ();     private FaceConversionUtil() {     }     public static FaceConversionUtil getInstace() {   if (mFaceConversionUtil == null) {   mFaceConversionUtil = new FaceConversionUtil();   }   return mFaceConversionUtil;   }     /**   * 得到一个SpanableString对象,通过传入的字符串,并进行正则判断   *   * @param context   * @param str   * @return   */   public SpannableString getExpressionString(Context context, String str) {   SpannableString spannableString = new SpannableString(str);   // 正则表达式比配字符串里是否含有表情,如: 我好[开心]啊   String zhengze =  //[[^//]]+//] ;   // 通过传入的正则表达式来生成一个pattern   Pattern sinaPatten = Pattern.compile(zhengze, Pattern.CASE_INSENSITIVE);   try {   dealExpression(context, spannableString, sinaPatten, 0);   } catch (Exception e) {   Log.e( dealExpression , e.getMessage());   }   return spannableString;   }     /**   * 添加表情   *   * @param context   * @param imgId   * @param spannableString   * @return   */   public SpannableString addFace(Context context, int imgId,   String spannableString) {   if (TextUtils.isEmpty(spannableString)) {   return null;   }   Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(),   imgId);   bitmap = Bitmap.createScaledBitmap(bitmap, 35, 35, true);   ImageSpan imageSpan = new ImageSpan(context, bitmap);   SpannableString spannable = new SpannableString(spannableString);   spannable.setSpan(imageSpan, 0, spannableString.length(),   Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);   return spannable;   }     /**   * 对spanableString进行正则判断,如果符合要求,则以表情图片代替   *   * @param context   * @param spannableString   * @param patten   * @param start   * @throws Exception   */   private void dealExpression(Context context,   SpannableString spannableString, Pattern patten, int start)   throws Exception {   Matcher matcher = patten.matcher(spannableString);   while (matcher.find()) {   String key = matcher.group();   // 返回第一个字符的索引的文本匹配整个正则表达式,ture 则继续递归   if (matcher.start()   start) {   continue;   }   String value = emojiMap.get(key);   if (TextUtils.isEmpty(value)) {   continue;   }   int resId = context.getResources().getIdentifier(value,  drawable ,   context.getPackageName());   // 通过上面匹配得到的字符串来生成图片资源id,下边的方法可用,但是你工程混淆的时候就有事了,你懂的。不是我介绍的重点   // Field field=R.drawable.class.getDeclaredField(value);   // int resId=Integer.parseInt(field.get(null).toString());   if (resId != 0) {   Bitmap bitmap = BitmapFactory.decodeResource(   context.getResources(), resId);   bitmap = Bitmap.createScaledBitmap(bitmap, 50, 50, true);   // 通过图片资源id来得到bitmap,用一个ImageSpan来包装   ImageSpan imageSpan = new ImageSpan(bitmap);   // 计算该图片名字的长度,也就是要替换的字符串的长度   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;   }   }   }     public void getFileText(Context context) {   ParseData(FileUtils.getEmojiFile(context), context);   }     /**   * 解析字符   *   * @param data   */   private void ParseData(List String  data, Context context) {   if (data == null) {   return;   }   ChatEmoji emojEentry;   try {   for (String str : data) {   String[] text = str.split( , );   String fileName = text[0]   .substring(0, text[0].lastIndexOf( . ));   emojiMap.put(text[1], fileName);   int resID = context.getResources().getIdentifier(fileName,    drawable , context.getPackageName());     if (resID != 0) {   emojEentry = new ChatEmoji();   emojEentry.setId(resID);   emojEentry.setCharacter(text[1]);   emojEentry.setFaceName(fileName);   emojis.add(emojEentry);   }   }   int pageCount = (int) Math.ceil(emojis.size() / 20 + 0.1);     for (int i = 0; i   pageCount; i++) {   emojiLists.add(getData(i));   }   } catch (Exception e) {   e.printStackTrace();   }   }     /**   * 获取分页数据   *   * @param page   * @return   */   private List ChatEmoji  getData(int page) {   int startIndex = page * pageSize;   int endIndex = startIndex + pageSize;     if (endIndex   emojis.size()) {   endIndex = emojis.size();   }   // 不这么写,会在viewpager加载中报集合操作异常,我也不知道为什么   List ChatEmoji  list = new ArrayList ChatEmoji    list.addAll(emojis.subList(startIndex, endIndex));   if (list.size()   pageSize) {   for (int i = list.size(); i   pageSize; i++) {   ChatEmoji object = new ChatEmoji();   list.add(object);   }   }   if (list.size() == pageSize) {   ChatEmoji object = new ChatEmoji();   object.setId(R.drawable.face_del_icon);   list.add(object);   }   return list;   }  } 

下边是表情布局,带输入框的,这样可以多个地方使用,就不不会使用太多多余代码。


[java]
view plain
copy
print
? package com.example.facedemo;    import java.util.ArrayList;  import java.util.List;    import android.content.Context;  import android.graphics.Color;  import android.graphics.drawable.ColorDrawable;  import android.support.v4.view.ViewPager;  import android.support.v4.view.ViewPager.OnPageChangeListener;  import android.text.SpannableString;  import android.text.TextUtils;  import android.util.AttributeSet;  import android.view.Gravity;  import android.view.View;  import android.view.View.OnClickListener;  import android.view.ViewGroup;  import android.widget.AdapterView;  import android.widget.AdapterView.OnItemClickListener;  import android.widget.EditText;  import android.widget.GridView;  import android.widget.ImageView;  import android.widget.LinearLayout;  import android.widget.RelativeLayout;    /**   *   ******************************************   * @author 廖乃波   * @文件名称 : FaceRelativeLayout.java   * @创建时间 : 2013-1-27 下午02:34:17   * @文件描述 : 带表情的自定义输入框   ******************************************   */  public class FaceRelativeLayout extends RelativeLayout implements   OnItemClickListener, OnClickListener {     private Context context;     /** 表情页的监听事件 */   private OnCorpusSelectedListener mListener;     /** 显示表情页的viewpager */   private ViewPager vp_face;     /** 表情页界面集合 */   private ArrayList View  pageViews;     /** 游标显示布局 */   private LinearLayout layout_point;     /** 游标点集合 */   private ArrayList ImageView  pointViews;     /** 表情集合 */   private List List ChatEmoji  emojis;     /** 表情区域 */   private View view;     /** 输入框 */   private EditText et_sendmessage;     /** 表情数据填充器 */   private List FaceAdapter  faceAdapters;     /** 当前表情页 */   private int current = 0;     public FaceRelativeLayout(Context context) {   super(context);   this.context = context;   }     public FaceRelativeLayout(Context context, AttributeSet attrs) {   super(context, attrs);   this.context = context;   }     public FaceRelativeLayout(Context context, AttributeSet attrs, int defStyle) {   super(context, attrs, defStyle);   this.context = context;   }     public void setOnCorpusSelectedListener(OnCorpusSelectedListener listener) {   mListener = listener;   }     /**   * 表情选择监听   *   * @author naibo-liao   * @时间: 2013-1-15下午04:32:54   */   public interface OnCorpusSelectedListener {     void onCorpusSelected(ChatEmoji emoji);     void onCorpusDeleted();   }     @Override   protected void onFinishInflate() {   super.onFinishInflate();   emojis = FaceConversionUtil.getInstace().emojiLists;   onCreate();   }     private void onCreate() {   Init_View();   Init_viewPager();   Init_Point();   Init_Data();   }     @Override   public void onClick(View v) {   switch (v.getId()) {   case R.id.btn_face:   // 隐藏表情选择框   if (view.getVisibility() == View.VISIBLE) {   view.setVisibility(View.GONE);   } else {   view.setVisibility(View.VISIBLE);   }   break;   case R.id.et_sendmessage:   // 隐藏表情选择框   if (view.getVisibility() == View.VISIBLE) {   view.setVisibility(View.GONE);   }   break;     }   }     /**   * 隐藏表情选择框   */   public boolean hideFaceView() {   // 隐藏表情选择框   if (view.getVisibility() == View.VISIBLE) {   view.setVisibility(View.GONE);   return true;   }   return false;   }     /**   * 初始化控件   */   private void Init_View() {   vp_face = (ViewPager) findViewById(R.id.vp_contains);   et_sendmessage = (EditText) findViewById(R.id.et_sendmessage);   layout_point = (LinearLayout) findViewById(R.id.iv_image);   et_sendmessage.setOnClickListener(this);   findViewById(R.id.btn_face).setOnClickListener(this);   view = findViewById(R.id.ll_facechoose);     }     /**   * 初始化显示表情的viewpager   */   private void Init_viewPager() {   pageViews = new ArrayList View    // 左侧添加空页   View nullView1 = new View(context);   // 设置透明背景   nullView1.setBackgroundColor(Color.TRANSPARENT);   pageViews.add(nullView1);     // 中间添加表情页     faceAdapters = new ArrayList FaceAdapter    for (int i = 0; i   emojis.size(); i++) {   GridView view = new GridView(context);   FaceAdapter adapter = new FaceAdapter(context, emojis.get(i));   view.setAdapter(adapter);   faceAdapters.add(adapter);   view.setOnItemClickListener(this);   view.setNumColumns(7);   view.setBackgroundColor(Color.TRANSPARENT);   view.setHorizontalSpacing(1);   view.setVerticalSpacing(1);   view.setStretchMode(GridView.STRETCH_COLUMN_WIDTH);   view.setCacheColorHint(0);   view.setPadding(5, 0, 5, 0);   view.setSelector(new ColorDrawable(Color.TRANSPARENT));   view.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,   LayoutParams.WRAP_CONTENT));   view.setGravity(Gravity.CENTER);   pageViews.add(view);   }     // 右侧添加空页面   View nullView2 = new View(context);   // 设置透明背景   nullView2.setBackgroundColor(Color.TRANSPARENT);   pageViews.add(nullView2);   }     /**   * 初始化游标   */   private void Init_Point() {     pointViews = new ArrayList ImageView    ImageView imageView;   for (int i = 0; i   pageViews.size(); i++) {   imageView = new ImageView(context);   imageView.setBackgroundResource(R.drawable.d1);   LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(   new ViewGroup.LayoutParams(LayoutParams.WRAP_CONTENT,   LayoutParams.WRAP_CONTENT));   layoutParams.leftMargin = 10;   layoutParams.rightMargin = 10;   layoutParams.width = 8;   layoutParams.height = 8;   layout_point.addView(imageView, layoutParams);   if (i == 0 || i == pageViews.size()   1) {   imageView.setVisibility(View.GONE);   }   if (i == 1) {   imageView.setBackgroundResource(R.drawable.d2);   }   pointViews.add(imageView);     }   }     /**   * 填充数据   */   private void Init_Data() {   vp_face.setAdapter(new ViewPagerAdapter(pageViews));     vp_face.setCurrentItem(1);   current = 0;   vp_face.setOnPageChangeListener(new OnPageChangeListener() {     @Override   public void onPageSelected(int arg0) {   current = arg0   1;   // 描绘分页点   draw_Point(arg0);   // 如果是第一屏或者是最后一屏禁止滑动,其实这里实现的是如果滑动的是第一屏则跳转至第二屏,如果是最后一屏则跳转到倒数第二屏.   if (arg0 == pointViews.size()   1 || arg0 == 0) {   if (arg0 == 0) {   vp_face.setCurrentItem(arg0 + 1);// 第二屏 会再次实现该回调方法实现跳转.   pointViews.get(1).setBackgroundResource(R.drawable.d2);   } else {   vp_face.setCurrentItem(arg0   1);// 倒数第二屏   pointViews.get(arg0   1).setBackgroundResource(   R.drawable.d2);   }   }   }     @Override   public void onPageScrolled(int arg0, float arg1, int arg2) {     }     @Override   public void onPageScrollStateChanged(int arg0) {     }   });     }     /**   * 绘制游标背景   */   public void draw_Point(int index) {   for (int i = 1; i   pointViews.size(); i++) {   if (index == i) {   pointViews.get(i).setBackgroundResource(R.drawable.d2);   } else {   pointViews.get(i).setBackgroundResource(R.drawable.d1);   }   }   }     @Override   public void onItemClick(AdapterView ?  arg0, View arg1, int arg2, long arg3) {   ChatEmoji emoji = (ChatEmoji) faceAdapters.get(current).getItem(arg2);   if (emoji.getId() == R.drawable.face_del_icon) {   int selection = et_sendmessage.getSelectionStart();   String text = et_sendmessage.getText().toString();   if (selection   0) {   String text2 = text.substring(selection   1);   if ( ] .equals(text2)) {   int start = text.lastIndexOf( [ );   int end = selection;   et_sendmessage.getText().delete(start, end);   return;   }   et_sendmessage.getText().delete(selection   1, selection);   }   }   if (!TextUtils.isEmpty(emoji.getCharacter())) {   if (mListener != null)   mListener.onCorpusSelected(emoji);   SpannableString spannableString = FaceConversionUtil.getInstace()   .addFace(getContext(), emoji.getId(), emoji.getCharacter());   et_sendmessage.append(spannableString);   }     }  } 
[java]
view plain
copy
print
? package com.example.facedemo;    import android.content.Context;    import android.text.SpannableString;  import android.view.LayoutInflater;  import android.view.View;  import android.view.ViewGroup;    import android.widget.BaseAdapter;  import android.widget.TextView;    import java.util.List;    /**   *   ******************************************   * @author 廖乃波   * @文件名称 : ChatMsgAdapter.java   * @创建时间 : 2013-1-27 下午02:33:16   * @文件描述 : 消息数据填充起   ******************************************   */  public class ChatMsgAdapter extends BaseAdapter {     public static interface IMsgViewType {   int IMVT_COM_MSG = 0;   int IMVT_TO_MSG = 1;   }     private List ChatMsgEntity  coll;   private LayoutInflater mInflater;   private Context context;   public ChatMsgAdapter(Context context, List ChatMsgEntity  coll) {   this.coll = coll;   mInflater = LayoutInflater.from(context);   this.context = context;   }     public int getCount() {   return coll.size();   }     public Object getItem(int position) {   return coll.get(position);   }     public long getItemId(int position) {   return position;   }     public int getItemViewType(int position) {   ChatMsgEntity entity = coll.get(position);     if (entity.getMsgType()) {   return IMsgViewType.IMVT_COM_MSG;   } else {   return IMsgViewType.IMVT_TO_MSG;   }     }     public int getViewTypeCount() {   return 2;   }     public View getView(int position, View convertView, ViewGroup parent) {     ChatMsgEntity entity = coll.get(position);   boolean isComMsg = entity.getMsgType();     ViewHolder viewHolder = null;   if (convertView == null) {   if (isComMsg) {   convertView = mInflater.inflate(   R.layout.chatting_item_msg_text_left, null);   } else {   convertView = mInflater.inflate(   R.layout.chatting_item_msg_text_right, null);   }     viewHolder = new ViewHolder();   viewHolder.tvSendTime = (TextView) convertView   .findViewById(R.id.tv_sendtime);   viewHolder.tvContent = (TextView) convertView   .findViewById(R.id.tv_chatcontent);   viewHolder.isComMsg = isComMsg;     convertView.setTag(viewHolder);   } else {   viewHolder = (ViewHolder) convertView.getTag();   }     viewHolder.tvSendTime.setText(entity.getDate());   SpannableString spannableString = FaceConversionUtil.getInstace().getExpressionString(context, entity.getText());   viewHolder.tvContent.setText(spannableString);     return convertView;   }     class ViewHolder {   public TextView tvSendTime;   public TextView tvContent;   public boolean isComMsg = true;   }    } 
[java]
view plain
copy
print
? package com.example.facedemo;    import java.io.BufferedReader;  import java.io.IOException;  import java.io.InputStream;  import java.io.InputStreamReader;  import java.util.ArrayList;  import java.util.List;    import android.content.Context;    /**   *   ******************************************   * @author 廖乃波   * @文件名称 : FileUtils.java   * @创建时间 : 2013-1-27 下午02:35:09   * @文件描述 : 文件工具类   ******************************************   */  public class FileUtils {   /**   * 读取表情配置文件   *   * @param context   * @return   */   public static List String  getEmojiFile(Context context) {   try {   List String  list = new ArrayList String    InputStream in = context.getResources().getAssets().open( emoji );   BufferedReader br = new BufferedReader(new InputStreamReader(in,    UTF-8 ));   String str = null;   while ((str = br.readLine()) != null) {   list.add(str);   }     return list;   } catch (IOException e) {   e.printStackTrace();   }   return null;   }  } 
[java]
view plain
copy
print
? package com.example.facedemo;    import java.util.List;    import android.support.v4.view.PagerAdapter;  import android.support.v4.view.ViewPager;  import android.view.View;  /**   *   ******************************************   * @author 廖乃波   * @文件名称 : ViewPagerAdapter.java   * @创建时间 : 2013-1-27 下午02:35:27   * @文件描述 : ViewPager 数据填充器,切记做其他操作!!!只填充View!!!!   ******************************************   */  public class ViewPagerAdapter extends PagerAdapter {     private List View  pageViews;     public ViewPagerAdapter(List View  pageViews) {   super();   this.pageViews=pageViews;   }     // 显示数目   @Override   public int getCount() {   return pageViews.size();   }     @Override   public boolean isViewFromObject(View arg0, Object arg1) {   return arg0 == arg1;   }     @Override   public int getItemPosition(Object object) {   return super.getItemPosition(object);   }     @Override   public void destroyItem(View arg0, int arg1, Object arg2) {   ((ViewPager)arg0).removeView(pageViews.get(arg1));   }     /***   * 获取每一个item�?类于listview中的getview   */   @Override   public Object instantiateItem(View arg0, int arg1) {   ((ViewPager)arg0).addView(pageViews.get(arg1));   return pageViews.get(arg1);   }  } 
[java]
view plain
copy
print
? emoji_1.png,可爱  emoji_2.png,[笑脸]  emoji_3.png,[囧]  emoji_4.png,生气  emoji_5.png,[鬼脸]  emoji_6.png,[花心]  emoji_7.png,[害怕]  emoji_8.png,[我汗]  emoji_9.png,[尴尬]  emoji_10.png,[哼哼]  emoji_11.png,[忧郁]  emoji_12.png,[呲牙]  emoji_13.png,[媚眼]  emoji_14.png,[累]  emoji_15.png,[苦逼]  emoji_16.png,[瞌睡]  emoji_17.png,[哎呀]  emoji_18.png,[刺瞎]  emoji_19.png,[哭]  emoji_20.png,[激动]  emoji_21.png,难过  emoji_22.png,[害羞]  emoji_23.png,[高兴]  emoji_24.png,[愤怒]  emoji_25.png,[亲]  emoji_26.png,[飞吻]  emoji_27.png,[得意]  emoji_28.png,[惊恐]  emoji_29.png,[口罩]  emoji_30.png,[惊讶]  emoji_31.png,[委屈]  emoji_32.png,[生病]  emoji_33.png,[红心]  emoji_34.png,[心碎]  emoji_35.png,[玫瑰]  emoji_36.png,花  emoji_37.png,[外星人]  emoji_38.png,[金牛座]  emoji_39.png,[双子座]  emoji_40.png,[巨蟹座]  emoji_41.png,[狮子座]  emoji_42.png,[处女座]  emoji_43.png,[天平座]  emoji_44.png,[天蝎座]  emoji_45.png,[射手座]  emoji_46.png,[摩羯座]  emoji_47.png,[水瓶座]  emoji_48.png,[白羊座]  emoji_49.png,[双鱼座]  emoji_50.png,[星座]  emoji_51.png,[男孩]  emoji_52.png,[女孩]  emoji_53.png,[嘴唇]  emoji_54.png,[爸爸]  emoji_55.png,[妈妈]  emoji_56.png,[衣服]  emoji_57.png,[皮鞋]  emoji_58.png,[照相]  emoji_59.png,[电话]  emoji_60.png,[石头]  emoji_61.png,[胜利]  emoji_62.png,[禁止]  emoji_63.png,[滑雪]  emoji_64.png,[高尔夫]  emoji_65.png,[网球]  emoji_66.png,[棒球]  emoji_67.png,[冲浪]  emoji_68.png,[足球]  emoji_69.png,[小鱼]  emoji_70.png,[问号]  emoji_71.png,[叹号]  emoji_179.png,[顶]  emoji_180.png,[写字]  emoji_181.png,[衬衫]  emoji_182.png,[小花]  emoji_183.png,[郁金香]  emoji_184.png,[向日葵]  emoji_185.png,[鲜花]  emoji_186.png,[椰树]  emoji_187.png,[仙人掌]  emoji_188.png,[气球]  emoji_189.png,[炸弹]  emoji_190.png,喝彩  emoji_191.png,[剪子]  emoji_192.png,[蝴蝶结]  emoji_193.png,[机密]  emoji_194.png,[铃声]  emoji_195.png,[女帽]  emoji_196.png,[裙子]  emoji_197.png,[理发店]  emoji_198.png,[和服]  emoji_199.png,[比基尼]  emoji_200.png,[拎包]  emoji_201.png,[拍摄]  emoji_202.png,[铃铛]  emoji_203.png,[音乐]  emoji_204.png,[心星]  emoji_205.png,[粉心]  emoji_206.png,[丘比特]  emoji_207.png,[吹气]  emoji_208.png,[口水]  emoji_209.png,[对]  emoji_210.png,[错]  emoji_211.png,[绿茶]  emoji_212.png,[面包]  emoji_213.png,[面条]  emoji_214.png,[咖喱饭]  emoji_215.png,[饭团]  emoji_216.png,[麻辣烫]  emoji_217.png,[寿司]  emoji_218.png,[苹果]  emoji_219.png,[橙子]  emoji_220.png,[草莓]  emoji_221.png,[西瓜]  emoji_222.png,[柿子]  emoji_223.png,[眼睛]  emoji_224.png,[好的] 
[html]
view plain
copy
print
? ?xml version= 1.0  encoding= utf-8 ?   com.example.facedemo.FaceRelativeLayout xmlns:android= http://schemas.android.com/apk/res/android    android:id= @+id/FaceRelativeLayout    android:layout_width= fill_parent    android:layout_height= wrap_content         RelativeLayout   android:id= @+id/rl_input    android:layout_width= fill_parent    android:layout_height= wrap_content    android:background= @drawable/chat_footer_bg         ImageButton   android:id= @+id/btn_face    android:layout_width= 40dip    android:layout_height= 40dip    android:layout_alignParentLeft= true    android:layout_centerVertical= true    android:layout_marginLeft= 8dip    android:background= @drawable/chat_send_btn    android:src= @drawable/ib_face  /       Button   android:id= @+id/btn_send    android:layout_width= 60dp    android:layout_height= 40dp    android:layout_alignParentRight= true    android:layout_centerVertical= true    android:layout_marginRight= 10dp    android:background= @drawable/chat_send_btn    android:text= 发送  /       EditText   android:id= @+id/et_sendmessage    android:layout_width= fill_parent    android:layout_height= 40dp    android:layout_centerVertical= true    android:layout_marginLeft= 8dp    android:layout_marginRight= 10dp    android:layout_toLeftOf= @id/btn_send    android:layout_toRightOf= @id/btn_face    android:background= @drawable/login_edit_normal    android:singleLine= true    android:textSize= 18sp  /     /RelativeLayout       RelativeLayout   android:id= @+id/ll_facechoose    android:layout_width= fill_parent    android:layout_height= 124dip    android:layout_below= @id/rl_input    android:background= #f6f5f5    android:visibility= gone         android.support.v4.view.ViewPager   android:id= @+id/vp_contains    android:layout_width= match_parent    android:layout_height= match_parent       /android.support.v4.view.ViewPager       LinearLayout   android:id= @+id/iv_image    android:layout_width= match_parent    android:layout_height= wrap_content    android:layout_alignParentBottom= true    android:layout_marginBottom= 6dip    android:gravity= center    android:orientation= horizontal       /LinearLayout     /RelativeLayout     /com.example.facedemo.FaceRelativeLayout