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. Luogu2483 [SDOI2010]魔法猪学院(可并堆)

    俞鼎力大牛的课件 对于原图以 \(t\) 为根建出任意一棵最短路径树 \(T\),即反着从 \(t\) 跑出到所有点的最短路 \(dis\) 它有一些性质: 性质1: 对于一条 \(s\) 到 \(t ...

  2. Class.forName和ClassLoader.loadClass的区别(转载)

    Class的装载分了三个阶段,loading,linking和initializing,分别定义在The Java Language Specification的12.2,12.3和12.4.Clas ...

  3. Cloud Computing Causing Digital Business Transformation

    2015-04-13 Cloud Computing Causing Digital Business Transformation We hear all about the cloud, and  ...

  4. 50+ Useful Docker Tools

    As containers take root, dozens of tools have sprung up to support them. Check out your options for ...

  5. Python power spectral 功率谱

    You can also use scipy.signal.welch to estimate the power spectral density using Welch’s method. Her ...

  6. MySQL查询高速缓冲

    对mysql的优化不在行,搞过几次优化,但是都不是很理想,还是浪费资源太多.一直发现我的mysql的缓存命中率极差,情况良好的时候到达过60-70%,但是运行时间一长,只有10-20%.查了一些资料, ...

  7. 对WebSocket技术的学习与探索(一)

    WebSocket 简要介绍 WebSocket protocol 是HTML5一种新的协议. 它实现了浏览器与服务器全双工通信(full-duple). 一开始的握手需要借助HTTP请求完成. We ...

  8. mac自动生成路径问题

    使用myBatis的逆向工程,一直无法生成.最后找同事帮忙,最终发现是 :路径前面少加一个反斜杠... 也就是 mac的绝对路径 前面需要加上 反斜杠.

  9. C/C++内存对齐 ZZ

    这篇文章写得非常深入浅出.推荐.图需要到原博看. http://songlee24.github.io/2014/09/20/memory-alignment/ 下面是网易的一道笔试题:struct ...

  10. 装饰器( decorate )

    装饰器分步解释-形成过程: #-*- coding: UTF-8 -*- #示例1: def deco(p_args): def pack(): print('haha,i am deco fun') ...