http://blog.csdn.net/lnb333666/article/details/8546497

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

其次大致说说原理:

1,首先判断输入的字符,是否包含表情的文字,比如   这个表情对应的文件名为 emoji_1.png,它对应的文字描述
[可爱],如果我们在输出的是输出这么一句话:老婆,我想你了
 那么我们对应的根本文字就是:老婆,我想你了[可爱]

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

下面贴上DEMO工程的结构:

再贴上几个重要的类:

[java] view
plain
copy

  1. package com.example.facedemo;
  2. import java.util.ArrayList;
  3. import java.util.HashMap;
  4. import java.util.List;
  5. import java.util.regex.Matcher;
  6. import java.util.regex.Pattern;
  7. import android.content.Context;
  8. import android.graphics.Bitmap;
  9. import android.graphics.BitmapFactory;
  10. import android.text.Spannable;
  11. import android.text.SpannableString;
  12. import android.text.TextUtils;
  13. import android.text.style.ImageSpan;
  14. import android.util.Log;
  15. /**
  16. *
  17. ******************************************
  18. * @author 廖乃波
  19. * @文件名称 : FaceConversionUtil.java
  20. * @创建时间 : 2013-1-27 下午02:34:09
  21. * @文件描述 : 表情轉換工具
  22. ******************************************
  23. */
  24. public class FaceConversionUtil {
  25. /** 每一页表情的个数 */
  26. private int pageSize = 20;
  27. private static FaceConversionUtil mFaceConversionUtil;
  28. /** 保存于内存中的表情HashMap */
  29. private HashMap<String, String> emojiMap = new HashMap<String, String>();
  30. /** 保存于内存中的表情集合 */
  31. private List<ChatEmoji> emojis = new ArrayList<ChatEmoji>();
  32. /** 表情分页的结果集合 */
  33. public List<List<ChatEmoji>> emojiLists = new ArrayList<List<ChatEmoji>>();
  34. private FaceConversionUtil() {
  35. }
  36. public static FaceConversionUtil getInstace() {
  37. if (mFaceConversionUtil == null) {
  38. mFaceConversionUtil = new FaceConversionUtil();
  39. }
  40. return mFaceConversionUtil;
  41. }
  42. /**
  43. * 得到一个SpanableString对象,通过传入的字符串,并进行正则判断
  44. *
  45. * @param context
  46. * @param str
  47. * @return
  48. */
  49. public SpannableString getExpressionString(Context context, String str) {
  50. SpannableString spannableString = new SpannableString(str);
  51. // 正则表达式比配字符串里是否含有表情,如: 我好[开心]啊
  52. String zhengze = "\\[[^\\]]+\\]";
  53. // 通过传入的正则表达式来生成一个pattern
  54. Pattern sinaPatten = Pattern.compile(zhengze, Pattern.CASE_INSENSITIVE);
  55. try {
  56. dealExpression(context, spannableString, sinaPatten, 0);
  57. } catch (Exception e) {
  58. Log.e("dealExpression", e.getMessage());
  59. }
  60. return spannableString;
  61. }
  62. /**
  63. * 添加表情
  64. *
  65. * @param context
  66. * @param imgId
  67. * @param spannableString
  68. * @return
  69. */
  70. public SpannableString addFace(Context context, int imgId,
  71. String spannableString) {
  72. if (TextUtils.isEmpty(spannableString)) {
  73. return null;
  74. }
  75. Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(),
  76. imgId);
  77. bitmap = Bitmap.createScaledBitmap(bitmap, 35, 35, true);
  78. ImageSpan imageSpan = new ImageSpan(context, bitmap);
  79. SpannableString spannable = new SpannableString(spannableString);
  80. spannable.setSpan(imageSpan, 0, spannableString.length(),
  81. Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
  82. return spannable;
  83. }
  84. /**
  85. * 对spanableString进行正则判断,如果符合要求,则以表情图片代替
  86. *
  87. * @param context
  88. * @param spannableString
  89. * @param patten
  90. * @param start
  91. * @throws Exception
  92. */
  93. private void dealExpression(Context context,
  94. SpannableString spannableString, Pattern patten, int start)
  95. throws Exception {
  96. Matcher matcher = patten.matcher(spannableString);
  97. while (matcher.find()) {
  98. String key = matcher.group();
  99. // 返回第一个字符的索引的文本匹配整个正则表达式,ture 则继续递归
  100. if (matcher.start() < start) {
  101. continue;
  102. }
  103. String value = emojiMap.get(key);
  104. if (TextUtils.isEmpty(value)) {
  105. continue;
  106. }
  107. int resId = context.getResources().getIdentifier(value, "drawable",
  108. context.getPackageName());
  109. // 通过上面匹配得到的字符串来生成图片资源id,下边的方法可用,但是你工程混淆的时候就有事了,你懂的。不是我介绍的重点
  110. // Field field=R.drawable.class.getDeclaredField(value);
  111. // int resId=Integer.parseInt(field.get(null).toString());
  112. if (resId != 0) {
  113. Bitmap bitmap = BitmapFactory.decodeResource(
  114. context.getResources(), resId);
  115. bitmap = Bitmap.createScaledBitmap(bitmap, 50, 50, true);
  116. // 通过图片资源id来得到bitmap,用一个ImageSpan来包装
  117. ImageSpan imageSpan = new ImageSpan(bitmap);
  118. // 计算该图片名字的长度,也就是要替换的字符串的长度
  119. int end = matcher.start() + key.length();
  120. // 将该图片替换字符串中规定的位置中
  121. spannableString.setSpan(imageSpan, matcher.start(), end,
  122. Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
  123. if (end < spannableString.length()) {
  124. // 如果整个字符串还未验证完,则继续。。
  125. dealExpression(context, spannableString, patten, end);
  126. }
  127. break;
  128. }
  129. }
  130. }
  131. public void getFileText(Context context) {
  132. ParseData(FileUtils.getEmojiFile(context), context);
  133. }
  134. /**
  135. * 解析字符
  136. *
  137. * @param data
  138. */
  139. private void ParseData(List<String> data, Context context) {
  140. if (data == null) {
  141. return;
  142. }
  143. ChatEmoji emojEentry;
  144. try {
  145. for (String str : data) {
  146. String[] text = str.split(",");
  147. String fileName = text[0]
  148. .substring(0, text[0].lastIndexOf("."));
  149. emojiMap.put(text[1], fileName);
  150. int resID = context.getResources().getIdentifier(fileName,
  151. "drawable", context.getPackageName());
  152. if (resID != 0) {
  153. emojEentry = new ChatEmoji();
  154. emojEentry.setId(resID);
  155. emojEentry.setCharacter(text[1]);
  156. emojEentry.setFaceName(fileName);
  157. emojis.add(emojEentry);
  158. }
  159. }
  160. int pageCount = (int) Math.ceil(emojis.size() / 20 + 0.1);
  161. for (int i = 0; i < pageCount; i++) {
  162. emojiLists.add(getData(i));
  163. }
  164. } catch (Exception e) {
  165. e.printStackTrace();
  166. }
  167. }
  168. /**
  169. * 获取分页数据
  170. *
  171. * @param page
  172. * @return
  173. */
  174. private List<ChatEmoji> getData(int page) {
  175. int startIndex = page * pageSize;
  176. int endIndex = startIndex + pageSize;
  177. if (endIndex > emojis.size()) {
  178. endIndex = emojis.size();
  179. }
  180. // 不这么写,会在viewpager加载中报集合操作异常,我也不知道为什么
  181. List<ChatEmoji> list = new ArrayList<ChatEmoji>();
  182. list.addAll(emojis.subList(startIndex, endIndex));
  183. if (list.size() < pageSize) {
  184. for (int i = list.size(); i < pageSize; i++) {
  185. ChatEmoji object = new ChatEmoji();
  186. list.add(object);
  187. }
  188. }
  189. if (list.size() == pageSize) {
  190. ChatEmoji object = new ChatEmoji();
  191. object.setId(R.drawable.face_del_icon);
  192. list.add(object);
  193. }
  194. return list;
  195. }
  196. }

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

[java] view
plain
copy

  1. package com.example.facedemo;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. import android.content.Context;
  5. import android.graphics.Color;
  6. import android.graphics.drawable.ColorDrawable;
  7. import android.support.v4.view.ViewPager;
  8. import android.support.v4.view.ViewPager.OnPageChangeListener;
  9. import android.text.SpannableString;
  10. import android.text.TextUtils;
  11. import android.util.AttributeSet;
  12. import android.view.Gravity;
  13. import android.view.View;
  14. import android.view.View.OnClickListener;
  15. import android.view.ViewGroup;
  16. import android.widget.AdapterView;
  17. import android.widget.AdapterView.OnItemClickListener;
  18. import android.widget.EditText;
  19. import android.widget.GridView;
  20. import android.widget.ImageView;
  21. import android.widget.LinearLayout;
  22. import android.widget.RelativeLayout;
  23. /**
  24. *
  25. ******************************************
  26. * @author 廖乃波
  27. * @文件名称    :  FaceRelativeLayout.java
  28. * @创建时间    : 2013-1-27 下午02:34:17
  29. * @文件描述    : 带表情的自定义输入框
  30. ******************************************
  31. */
  32. public class FaceRelativeLayout extends RelativeLayout implements
  33. OnItemClickListener, OnClickListener {
  34. private Context context;
  35. /** 表情页的监听事件 */
  36. private OnCorpusSelectedListener mListener;
  37. /** 显示表情页的viewpager */
  38. private ViewPager vp_face;
  39. /** 表情页界面集合 */
  40. private ArrayList<View> pageViews;
  41. /** 游标显示布局 */
  42. private LinearLayout layout_point;
  43. /** 游标点集合 */
  44. private ArrayList<ImageView> pointViews;
  45. /** 表情集合 */
  46. private List<List<ChatEmoji>> emojis;
  47. /** 表情区域 */
  48. private View view;
  49. /** 输入框 */
  50. private EditText et_sendmessage;
  51. /** 表情数据填充器 */
  52. private List<FaceAdapter> faceAdapters;
  53. /** 当前表情页 */
  54. private int current = 0;
  55. public FaceRelativeLayout(Context context) {
  56. super(context);
  57. this.context = context;
  58. }
  59. public FaceRelativeLayout(Context context, AttributeSet attrs) {
  60. super(context, attrs);
  61. this.context = context;
  62. }
  63. public FaceRelativeLayout(Context context, AttributeSet attrs, int defStyle) {
  64. super(context, attrs, defStyle);
  65. this.context = context;
  66. }
  67. public void setOnCorpusSelectedListener(OnCorpusSelectedListener listener) {
  68. mListener = listener;
  69. }
  70. /**
  71. * 表情选择监听
  72. *
  73. * @author naibo-liao
  74. * @时间: 2013-1-15下午04:32:54
  75. */
  76. public interface OnCorpusSelectedListener {
  77. void onCorpusSelected(ChatEmoji emoji);
  78. void onCorpusDeleted();
  79. }
  80. @Override
  81. protected void onFinishInflate() {
  82. super.onFinishInflate();
  83. emojis = FaceConversionUtil.getInstace().emojiLists;
  84. onCreate();
  85. }
  86. private void onCreate() {
  87. Init_View();
  88. Init_viewPager();
  89. Init_Point();
  90. Init_Data();
  91. }
  92. @Override
  93. public void onClick(View v) {
  94. switch (v.getId()) {
  95. case R.id.btn_face:
  96. // 隐藏表情选择框
  97. if (view.getVisibility() == View.VISIBLE) {
  98. view.setVisibility(View.GONE);
  99. } else {
  100. view.setVisibility(View.VISIBLE);
  101. }
  102. break;
  103. case R.id.et_sendmessage:
  104. // 隐藏表情选择框
  105. if (view.getVisibility() == View.VISIBLE) {
  106. view.setVisibility(View.GONE);
  107. }
  108. break;
  109. }
  110. }
  111. /**
  112. * 隐藏表情选择框
  113. */
  114. public boolean hideFaceView() {
  115. // 隐藏表情选择框
  116. if (view.getVisibility() == View.VISIBLE) {
  117. view.setVisibility(View.GONE);
  118. return true;
  119. }
  120. return false;
  121. }
  122. /**
  123. * 初始化控件
  124. */
  125. private void Init_View() {
  126. vp_face = (ViewPager) findViewById(R.id.vp_contains);
  127. et_sendmessage = (EditText) findViewById(R.id.et_sendmessage);
  128. layout_point = (LinearLayout) findViewById(R.id.iv_image);
  129. et_sendmessage.setOnClickListener(this);
  130. findViewById(R.id.btn_face).setOnClickListener(this);
  131. view = findViewById(R.id.ll_facechoose);
  132. }
  133. /**
  134. * 初始化显示表情的viewpager
  135. */
  136. private void Init_viewPager() {
  137. pageViews = new ArrayList<View>();
  138. // 左侧添加空页
  139. View nullView1 = new View(context);
  140. // 设置透明背景
  141. nullView1.setBackgroundColor(Color.TRANSPARENT);
  142. pageViews.add(nullView1);
  143. // 中间添加表情页
  144. faceAdapters = new ArrayList<FaceAdapter>();
  145. for (int i = 0; i < emojis.size(); i++) {
  146. GridView view = new GridView(context);
  147. FaceAdapter adapter = new FaceAdapter(context, emojis.get(i));
  148. view.setAdapter(adapter);
  149. faceAdapters.add(adapter);
  150. view.setOnItemClickListener(this);
  151. view.setNumColumns(7);
  152. view.setBackgroundColor(Color.TRANSPARENT);
  153. view.setHorizontalSpacing(1);
  154. view.setVerticalSpacing(1);
  155. view.setStretchMode(GridView.STRETCH_COLUMN_WIDTH);
  156. view.setCacheColorHint(0);
  157. view.setPadding(5, 0, 5, 0);
  158. view.setSelector(new ColorDrawable(Color.TRANSPARENT));
  159. view.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
  160. LayoutParams.WRAP_CONTENT));
  161. view.setGravity(Gravity.CENTER);
  162. pageViews.add(view);
  163. }
  164. // 右侧添加空页面
  165. View nullView2 = new View(context);
  166. // 设置透明背景
  167. nullView2.setBackgroundColor(Color.TRANSPARENT);
  168. pageViews.add(nullView2);
  169. }
  170. /**
  171. * 初始化游标
  172. */
  173. private void Init_Point() {
  174. pointViews = new ArrayList<ImageView>();
  175. ImageView imageView;
  176. for (int i = 0; i < pageViews.size(); i++) {
  177. imageView = new ImageView(context);
  178. imageView.setBackgroundResource(R.drawable.d1);
  179. LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
  180. new ViewGroup.LayoutParams(LayoutParams.WRAP_CONTENT,
  181. LayoutParams.WRAP_CONTENT));
  182. layoutParams.leftMargin = 10;
  183. layoutParams.rightMargin = 10;
  184. layoutParams.width = 8;
  185. layoutParams.height = 8;
  186. layout_point.addView(imageView, layoutParams);
  187. if (i == 0 || i == pageViews.size() - 1) {
  188. imageView.setVisibility(View.GONE);
  189. }
  190. if (i == 1) {
  191. imageView.setBackgroundResource(R.drawable.d2);
  192. }
  193. pointViews.add(imageView);
  194. }
  195. }
  196. /**
  197. * 填充数据
  198. */
  199. private void Init_Data() {
  200. vp_face.setAdapter(new ViewPagerAdapter(pageViews));
  201. vp_face.setCurrentItem(1);
  202. current = 0;
  203. vp_face.setOnPageChangeListener(new OnPageChangeListener() {
  204. @Override
  205. public void onPageSelected(int arg0) {
  206. current = arg0 - 1;
  207. // 描绘分页点
  208. draw_Point(arg0);
  209. // 如果是第一屏或者是最后一屏禁止滑动,其实这里实现的是如果滑动的是第一屏则跳转至第二屏,如果是最后一屏则跳转到倒数第二屏.
  210. if (arg0 == pointViews.size() - 1 || arg0 == 0) {
  211. if (arg0 == 0) {
  212. vp_face.setCurrentItem(arg0 + 1);// 第二屏 会再次实现该回调方法实现跳转.
  213. pointViews.get(1).setBackgroundResource(R.drawable.d2);
  214. } else {
  215. vp_face.setCurrentItem(arg0 - 1);// 倒数第二屏
  216. pointViews.get(arg0 - 1).setBackgroundResource(
  217. R.drawable.d2);
  218. }
  219. }
  220. }
  221. @Override
  222. public void onPageScrolled(int arg0, float arg1, int arg2) {
  223. }
  224. @Override
  225. public void onPageScrollStateChanged(int arg0) {
  226. }
  227. });
  228. }
  229. /**
  230. * 绘制游标背景
  231. */
  232. public void draw_Point(int index) {
  233. for (int i = 1; i < pointViews.size(); i++) {
  234. if (index == i) {
  235. pointViews.get(i).setBackgroundResource(R.drawable.d2);
  236. } else {
  237. pointViews.get(i).setBackgroundResource(R.drawable.d1);
  238. }
  239. }
  240. }
  241. @Override
  242. public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
  243. ChatEmoji emoji = (ChatEmoji) faceAdapters.get(current).getItem(arg2);
  244. if (emoji.getId() == R.drawable.face_del_icon) {
  245. int selection = et_sendmessage.getSelectionStart();
  246. String text = et_sendmessage.getText().toString();
  247. if (selection > 0) {
  248. String text2 = text.substring(selection - 1);
  249. if ("]".equals(text2)) {
  250. int start = text.lastIndexOf("[");
  251. int end = selection;
  252. et_sendmessage.getText().delete(start, end);
  253. return;
  254. }
  255. et_sendmessage.getText().delete(selection - 1, selection);
  256. }
  257. }
  258. if (!TextUtils.isEmpty(emoji.getCharacter())) {
  259. if (mListener != null)
  260. mListener.onCorpusSelected(emoji);
  261. SpannableString spannableString = FaceConversionUtil.getInstace()
  262. .addFace(getContext(), emoji.getId(), emoji.getCharacter());
  263. et_sendmessage.append(spannableString);
  264. }
  265. }
  266. }

接下来是聊天数据填充器的

[java] view
plain
copy

  1. package com.example.facedemo;
  2. import android.content.Context;
  3. import android.text.SpannableString;
  4. import android.view.LayoutInflater;
  5. import android.view.View;
  6. import android.view.ViewGroup;
  7. import android.widget.BaseAdapter;
  8. import android.widget.TextView;
  9. import java.util.List;
  10. /**
  11. *
  12. ******************************************
  13. * @author 廖乃波
  14. * @文件名称    :  ChatMsgAdapter.java
  15. * @创建时间    : 2013-1-27 下午02:33:16
  16. * @文件描述    : 消息数据填充起
  17. ******************************************
  18. */
  19. public class ChatMsgAdapter extends BaseAdapter {
  20. public static interface IMsgViewType {
  21. int IMVT_COM_MSG = 0;
  22. int IMVT_TO_MSG = 1;
  23. }
  24. private List<ChatMsgEntity> coll;
  25. private LayoutInflater mInflater;
  26. private Context context;
  27. public ChatMsgAdapter(Context context, List<ChatMsgEntity> coll) {
  28. this.coll = coll;
  29. mInflater = LayoutInflater.from(context);
  30. this.context = context;
  31. }
  32. public int getCount() {
  33. return coll.size();
  34. }
  35. public Object getItem(int position) {
  36. return coll.get(position);
  37. }
  38. public long getItemId(int position) {
  39. return position;
  40. }
  41. public int getItemViewType(int position) {
  42. ChatMsgEntity entity = coll.get(position);
  43. if (entity.getMsgType()) {
  44. return IMsgViewType.IMVT_COM_MSG;
  45. } else {
  46. return IMsgViewType.IMVT_TO_MSG;
  47. }
  48. }
  49. public int getViewTypeCount() {
  50. return 2;
  51. }
  52. public View getView(int position, View convertView, ViewGroup parent) {
  53. ChatMsgEntity entity = coll.get(position);
  54. boolean isComMsg = entity.getMsgType();
  55. ViewHolder viewHolder = null;
  56. if (convertView == null) {
  57. if (isComMsg) {
  58. convertView = mInflater.inflate(
  59. R.layout.chatting_item_msg_text_left, null);
  60. } else {
  61. convertView = mInflater.inflate(
  62. R.layout.chatting_item_msg_text_right, null);
  63. }
  64. viewHolder = new ViewHolder();
  65. viewHolder.tvSendTime = (TextView) convertView
  66. .findViewById(R.id.tv_sendtime);
  67. viewHolder.tvContent = (TextView) convertView
  68. .findViewById(R.id.tv_chatcontent);
  69. viewHolder.isComMsg = isComMsg;
  70. convertView.setTag(viewHolder);
  71. } else {
  72. viewHolder = (ViewHolder) convertView.getTag();
  73. }
  74. viewHolder.tvSendTime.setText(entity.getDate());
  75. SpannableString spannableString = FaceConversionUtil.getInstace().getExpressionString(context, entity.getText());
  76. viewHolder.tvContent.setText(spannableString);
  77. return convertView;
  78. }
  79. class ViewHolder {
  80. public TextView tvSendTime;
  81. public TextView tvContent;
  82. public boolean isComMsg = true;
  83. }
  84. }

最开始要读取的表情配置文件

[java] view
plain
copy

  1. package com.example.facedemo;
  2. import java.io.BufferedReader;
  3. import java.io.IOException;
  4. import java.io.InputStream;
  5. import java.io.InputStreamReader;
  6. import java.util.ArrayList;
  7. import java.util.List;
  8. import android.content.Context;
  9. /**
  10. *
  11. ******************************************
  12. * @author 廖乃波
  13. * @文件名称    :  FileUtils.java
  14. * @创建时间    : 2013-1-27 下午02:35:09
  15. * @文件描述    : 文件工具类
  16. ******************************************
  17. */
  18. public class FileUtils {
  19. /**
  20. * 读取表情配置文件
  21. *
  22. * @param context
  23. * @return
  24. */
  25. public static List<String> getEmojiFile(Context context) {
  26. try {
  27. List<String> list = new ArrayList<String>();
  28. InputStream in = context.getResources().getAssets().open("emoji");
  29. BufferedReader br = new BufferedReader(new InputStreamReader(in,
  30. "UTF-8"));
  31. String str = null;
  32. while ((str = br.readLine()) != null) {
  33. list.add(str);
  34. }
  35. return list;
  36. } catch (IOException e) {
  37. e.printStackTrace();
  38. }
  39. return null;
  40. }
  41. }

下边这个是表情翻页的数据填充,用的是viewpager,每一页填充的是一个gridview

[java] view
plain
copy

  1. package com.example.facedemo;
  2. import java.util.List;
  3. import android.support.v4.view.PagerAdapter;
  4. import android.support.v4.view.ViewPager;
  5. import android.view.View;
  6. /**
  7. *
  8. ******************************************
  9. * @author 廖乃波
  10. * @文件名称    :  ViewPagerAdapter.java
  11. * @创建时间    : 2013-1-27 下午02:35:27
  12. * @文件描述    : ViewPager 数据填充器,切记做其他操作!!!只填充View!!!!
  13. ******************************************
  14. */
  15. public class ViewPagerAdapter extends PagerAdapter {
  16. private List<View> pageViews;
  17. public ViewPagerAdapter(List<View> pageViews) {
  18. super();
  19. this.pageViews=pageViews;
  20. }
  21. // 显示数目
  22. @Override
  23. public int getCount() {
  24. return pageViews.size();
  25. }
  26. @Override
  27. public boolean isViewFromObject(View arg0, Object arg1) {
  28. return arg0 == arg1;
  29. }
  30. @Override
  31. public int getItemPosition(Object object) {
  32. return super.getItemPosition(object);
  33. }
  34. @Override
  35. public void destroyItem(View arg0, int arg1, Object arg2) {
  36. ((ViewPager)arg0).removeView(pageViews.get(arg1));
  37. }
  38. /***
  39. * 获取每一个item�?类于listview中的getview
  40. */
  41. @Override
  42. public Object instantiateItem(View arg0, int arg1) {
  43. ((ViewPager)arg0).addView(pageViews.get(arg1));
  44. return pageViews.get(arg1);
  45. }
  46. }

最后呢,是表情的配置文件,你想怎么搞都行,我就这么搞的

[java] view
plain
copy

  1. emoji_1.png,[可爱]
  2. emoji_2.png,[笑脸]
  3. emoji_3.png,[囧]
  4. emoji_4.png,[生气]
  5. emoji_5.png,[鬼脸]
  6. emoji_6.png,[花心]
  7. emoji_7.png,[害怕]
  8. emoji_8.png,[我汗]
  9. emoji_9.png,[尴尬]
  10. emoji_10.png,[哼哼]
  11. emoji_11.png,[忧郁]
  12. emoji_12.png,[呲牙]
  13. emoji_13.png,[媚眼]
  14. emoji_14.png,[累]
  15. emoji_15.png,[苦逼]
  16. emoji_16.png,[瞌睡]
  17. emoji_17.png,[哎呀]
  18. emoji_18.png,[刺瞎]
  19. emoji_19.png,[哭]
  20. emoji_20.png,[激动]
  21. emoji_21.png,[难过]
  22. emoji_22.png,[害羞]
  23. emoji_23.png,[高兴]
  24. emoji_24.png,[愤怒]
  25. emoji_25.png,[亲]
  26. emoji_26.png,[飞吻]
  27. emoji_27.png,[得意]
  28. emoji_28.png,[惊恐]
  29. emoji_29.png,[口罩]
  30. emoji_30.png,[惊讶]
  31. emoji_31.png,[委屈]
  32. emoji_32.png,[生病]
  33. emoji_33.png,[红心]
  34. emoji_34.png,[心碎]
  35. emoji_35.png,[玫瑰]
  36. emoji_36.png,[花]
  37. emoji_37.png,[外星人]
  38. emoji_38.png,[金牛座]
  39. emoji_39.png,[双子座]
  40. emoji_40.png,[巨蟹座]
  41. emoji_41.png,[狮子座]
  42. emoji_42.png,[处女座]
  43. emoji_43.png,[天平座]
  44. emoji_44.png,[天蝎座]
  45. emoji_45.png,[射手座]
  46. emoji_46.png,[摩羯座]
  47. emoji_47.png,[水瓶座]
  48. emoji_48.png,[白羊座]
  49. emoji_49.png,[双鱼座]
  50. emoji_50.png,[星座]
  51. emoji_51.png,[男孩]
  52. emoji_52.png,[女孩]
  53. emoji_53.png,[嘴唇]
  54. emoji_54.png,[爸爸]
  55. emoji_55.png,[妈妈]
  56. emoji_56.png,[衣服]
  57. emoji_57.png,[皮鞋]
  58. emoji_58.png,[照相]
  59. emoji_59.png,[电话]
  60. emoji_60.png,[石头]
  61. emoji_61.png,[胜利]
  62. emoji_62.png,[禁止]
  63. emoji_63.png,[滑雪]
  64. emoji_64.png,[高尔夫]
  65. emoji_65.png,[网球]
  66. emoji_66.png,[棒球]
  67. emoji_67.png,[冲浪]
  68. emoji_68.png,[足球]
  69. emoji_69.png,[小鱼]
  70. emoji_70.png,[问号]
  71. emoji_71.png,[叹号]
  72. emoji_179.png,[顶]
  73. emoji_180.png,[写字]
  74. emoji_181.png,[衬衫]
  75. emoji_182.png,[小花]
  76. emoji_183.png,[郁金香]
  77. emoji_184.png,[向日葵]
  78. emoji_185.png,[鲜花]
  79. emoji_186.png,[椰树]
  80. emoji_187.png,[仙人掌]
  81. emoji_188.png,[气球]
  82. emoji_189.png,[炸弹]
  83. emoji_190.png,[喝彩]
  84. emoji_191.png,[剪子]
  85. emoji_192.png,[蝴蝶结]
  86. emoji_193.png,[机密]
  87. emoji_194.png,[铃声]
  88. emoji_195.png,[女帽]
  89. emoji_196.png,[裙子]
  90. emoji_197.png,[理发店]
  91. emoji_198.png,[和服]
  92. emoji_199.png,[比基尼]
  93. emoji_200.png,[拎包]
  94. emoji_201.png,[拍摄]
  95. emoji_202.png,[铃铛]
  96. emoji_203.png,[音乐]
  97. emoji_204.png,[心星]
  98. emoji_205.png,[粉心]
  99. emoji_206.png,[丘比特]
  100. emoji_207.png,[吹气]
  101. emoji_208.png,[口水]
  102. emoji_209.png,[对]
  103. emoji_210.png,[错]
  104. emoji_211.png,[绿茶]
  105. emoji_212.png,[面包]
  106. emoji_213.png,[面条]
  107. emoji_214.png,[咖喱饭]
  108. emoji_215.png,[饭团]
  109. emoji_216.png,[麻辣烫]
  110. emoji_217.png,[寿司]
  111. emoji_218.png,[苹果]
  112. emoji_219.png,[橙子]
  113. emoji_220.png,[草莓]
  114. emoji_221.png,[西瓜]
  115. emoji_222.png,[柿子]
  116. emoji_223.png,[眼睛]
  117. emoji_224.png,[好的]

忘了布局文件,哇哈哈

[html] view
plain
copy

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <com.example.facedemo.FaceRelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:id="@+id/FaceRelativeLayout"
  4. android:layout_width="fill_parent"
  5. android:layout_height="wrap_content" >
  6. <RelativeLayout
  7. android:id="@+id/rl_input"
  8. android:layout_width="fill_parent"
  9. android:layout_height="wrap_content"
  10. android:background="@drawable/chat_footer_bg" >
  11. <ImageButton
  12. android:id="@+id/btn_face"
  13. android:layout_width="40dip"
  14. android:layout_height="40dip"
  15. android:layout_alignParentLeft="true"
  16. android:layout_centerVertical="true"
  17. android:layout_marginLeft="8dip"
  18. android:background="@drawable/chat_send_btn"
  19. android:src="@drawable/ib_face" />
  20. <Button
  21. android:id="@+id/btn_send"
  22. android:layout_width="60dp"
  23. android:layout_height="40dp"
  24. android:layout_alignParentRight="true"
  25. android:layout_centerVertical="true"
  26. android:layout_marginRight="10dp"
  27. android:background="@drawable/chat_send_btn"
  28. android:text="发送" />
  29. <EditText
  30. android:id="@+id/et_sendmessage"
  31. android:layout_width="fill_parent"
  32. android:layout_height="40dp"
  33. android:layout_centerVertical="true"
  34. android:layout_marginLeft="8dp"
  35. android:layout_marginRight="10dp"
  36. android:layout_toLeftOf="@id/btn_send"
  37. android:layout_toRightOf="@id/btn_face"
  38. android:background="@drawable/login_edit_normal"
  39. android:singleLine="true"
  40. android:textSize="18sp" />
  41. </RelativeLayout>
  42. <RelativeLayout
  43. android:id="@+id/ll_facechoose"
  44. android:layout_width="fill_parent"
  45. android:layout_height="124dip"
  46. android:layout_below="@id/rl_input"
  47. android:background="#f6f5f5"
  48. android:visibility="gone" >
  49. <android.support.v4.view.ViewPager
  50. android:id="@+id/vp_contains"
  51. android:layout_width="match_parent"
  52. android:layout_height="match_parent" >
  53. </android.support.v4.view.ViewPager>
  54. <LinearLayout
  55. android:id="@+id/iv_image"
  56. android:layout_width="match_parent"
  57. android:layout_height="wrap_content"
  58. android:layout_alignParentBottom="true"
  59. android:layout_marginBottom="6dip"
  60. android:gravity="center"
  61. android:orientation="horizontal" >
  62. </LinearLayout>
  63. </RelativeLayout>
  64. </com.example.facedemo.FaceRelativeLayout>

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 源码 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

免费下载

Android UI【android 仿微信、QQ聊天,带表情,可翻页,带翻页拖动缓冲】的更多相关文章

  1. Android之高仿手机QQ聊天

    源代码下载 转载请注明出处,谢谢! 最终版已上传.优化下拉刷新.增加来消息声音提示.主界面改成ViewPager,实现左右滑动.新增群组.最近会话显示条数,开始上班了,不再修改了.谢谢! 国庆这几天, ...

  2. Tauri-Vue3桌面端聊天室|tauri+vite3仿微信|tauri聊天程序EXE

    基于tauri+vue3.js+vite3跨桌面端仿微信聊天实例TauriVue3Chat. tauri-chat 运用最新tauri+vue3+vite3+element-plus+v3layer等 ...

  3. [Android] Android 手机下 仿 微信 客户端 界面 -- 微聊

    Android 手机下 仿 微信 客户端 界面 -- 微聊 (包括聊天列表 + 聊天对话页 + 朋友圈列表页 + 我的/发现 列表页) 项目演示: 功能说明: 1)底部标签切换 (TabHost + ...

  4. Vue3.0网页版聊天|Vue3.x+ElementPlus仿微信/QQ界面|vue3聊天实例

    一.项目简介 基于vue3.x+vuex+vue-router+element-plus+v3layer+v3scroll等技术构建的仿微信web桌面端聊天实战项目Vue3-Webchat.基本上实现 ...

  5. 【手把手教程】uniapp + vue 从0搭建仿微信App聊天应用:腾讯云TXIM即时通讯的最佳实践

    基于uniapp + vue 实现仿微信App聊天应用实践,实现以下功能 1: 用户登陆 2: 聊天会话管理 3: 文本/图片/视频/定位消息收发 4: 贴图表情消息收发 5: 一对一语音视频在线通话 ...

  6. uniapp+nvue实现仿微信App聊天应用 —— 成功实现好友聊天+语音视频通话功能

    基于uniapp + nvue实现的uniapp仿微信App聊天应用 txim 实例项目,实现了以下功能. 1: 聊天会话管理 2: 好友列表 3: 文字.语音.视频.表情.位置等聊天消息收发 4: ...

  7. h5移动端聊天室|仿微信界面聊天室|h5多人聊天室

    今年的FIFA世界杯甚是精彩,最近兴致高涨就利用HTML5开发了一个手机端仿微信界面聊天室,该h5聊天室采用750px全新伸缩flex布局,以及使用rem响应式配合fontsize.js,页面弹窗则是 ...

  8. WPF仿QQ聊天框表情文字混排实现

    原文:WPF仿QQ聊天框表情文字混排实现 二话不说.先上图 图中分别有文件.文本+表情.纯文本的展示,对于同一个list不同的展示形式,很明显,应该用多个DataTemplate,那么也就需要Data ...

  9. Android仿微信QQ等实现锁屏消息提醒

    demo代码如下: import android.content.Intent; import android.os.Bundle; import android.support.v7.app.App ...

  10. Android 高仿微信语音聊天页面高斯模糊效果

    目前的应用市场上,使用毛玻璃效果的APP随处可见,比如用过微信语音聊天的人可以发现,语音聊天页面就使用了高斯模糊效果. 先看下效果图: 仔细观察上图,我们可以发现,背景图以用户头像为模板,对其进行了高 ...

随机推荐

  1. java设计模式-----8、策略模式

    Strategy模式也叫策略模式是行为模式之一,它对一系列的算法加以封装,为所有算法定义一个抽象的算法接口,并通过继承该抽象算法接口对所有的算法加以封装和实现,具体的算法选择交由客户端决定(策略).S ...

  2. BZOJ2960:跨平面

    题面 BZOJ Sol 对该平面图的对偶图建图后就是最小树形图,建一个超级点向每个点连 \(inf\) 边即可 怎么转成对偶图,怎么弄出多边形 把边拆成两条有向边,分别挂在两个点上 每个点的出边按角度 ...

  3. js判断是手机还是PC端

    有时接触一些手机上的适应,需要知道是pc 还是移动端 function IsPC() { var userAgentInfo = navigator.userAgent; var Agents = [ ...

  4. Arcgis GDB文件地理数据库、shapefile、coverage 和其他基于文件的数据源所支持的函数的完整列表

    函数 以下是文件地理数据库.shapefile.coverage 和其他基于文件的数据源所支持的函数的完整列表.个人地理数据库和 ArcSDE 地理数据库也支持这些函数,但这些数据源可能使用不同的语法 ...

  5. Windows 10 Framework 3.5 _x64 离线安装包 最新安装版

    原文:http://www.jb51.net/softs/325481.html Windows 10 Framework 3.5 离线安装包,适用于 Win10 和 Server 2016 离线安装 ...

  6. 软工读书笔记 week2

    <程序员修炼之道>这本书后面一部分则是更深入.更具体.更细致地就程序员应该注意的事项做一些讨论,书中说的很多在过去的经历中都有较深的体会,同时也给了我很多启发.以下是一些我感悟较深的点: ...

  7. mac 下常用快捷键

    1.快速搜索某个类 双击thift 2.切换不同的类: ctrl+方向键 3.alt+command+B 进入到具体的子类 但是 ctrl+方向键一直切的是电脑上 桌面的切换.打开 系统偏好设置-快捷 ...

  8. window 7 & 2008R2 多核cpu套接字泄露补丁

    http://hotfixv4.microsoft.com/Windows%207/Windows%20Server2008%20R2%20SP1/sp2/Fix373886/7600/free/43 ...

  9. CentOS7.x使用yum安装Mysql5.6

    先检查是否存在已安装的MySQL # yum list installed | grep mysql 若存在删除: yum remove 软件名称 CentOS 7的yum源中没有正常安装mysql时 ...

  10. 监控事件日志关键字规则(EventDescription)

    新建规则--基于NT事件日志--自定义条件:EventDescription - 包含 - 关键字