Android UI【android 仿微信、QQ聊天,带表情,可翻页,带翻页拖动缓冲】

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>

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

免费下载

时间: 2024-10-09 20:00:51

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

Android 仿微信QQ聊天界面

一些IM聊天软件的展现形式是左右分开的形式.比如说,别人给你发的信息全部靠左显示,你自己发给别人的信息全部靠右显示. 而我们的ListView很多时候是显示同一个布局,其实BaseAdapter中有2个重要的方法在大多数情况下我们并未使用到,一个是public int getViewTypeCount(),显示ListView中有多少种布局(默认是显示是1),像微信那样聊天界面,是有2种布局方式:另外一个getItemViewType(),可以让不同item条目加载不同的布局,下面就简单的模拟下

Android仿微信语音聊天

完整代码下载地址: Android仿微信语音聊天 效果图: 分析: 1.自定义Button中要复写onTouchEvent的DOWN,MOVE,UP三种状态,对正常按下,想要取消发送,抬起三种动作进行侦听处理. 2.Dialog共有三种状态,除上图所示的两种外,还有一个录音时间过短的提示.其中录音状态中的音量可以变化. 3.显示录音的ListView的item中有一个录音时长(TextView),一个播放动画(View)和一个头像(ImageView). 4.录音类里有两个成员:录音长度,录音路

基于百度云推送的高仿微信实时聊天Android源码

基于百度云推送的高仿微信实时聊天Android源码 使用服务:百度云推送    功能分类:社交     支持平台:Android 运行环境:Android       开发语言:Java     开发工具:Eclipse 下载地址:http://sina.lt/z84 源码简介 基于百度云推送的一款Android高仿微信的实时聊天app 运行动态图

一款基于微客服的仿微信的聊天软件

一款基于微客服的仿微信的聊天软件 服务分类: 其它开发,推送 使用服务: 微客服 , 小米推送 功能分类: 社交 支持平台: Android 运行环境: Android 开发语言: Java 开发工具: Eclipse 源码大小: 7.11MB 下载地址:http://www.devstore.cn/code/info/68.html 源码简介 通过集成微客服的SDK和小米推送等常用SDK实现一款仿微信聊天的工具. 源码片段 源码运行截图 热门源码下载: 高仿京东商城 Android快速开发不可

【源码分享下载】一款基于微客服的仿微信的聊天软件

一款基于微客服的仿微信的聊天软件 服务分类: 其它开发,推送 使用服务: 微客服 , 小米推送 功能分类: 社交 支持平台: Android 运行环境: Android 开发语言: Java 开发工具: Eclipse 源码大小: 7.11MB 下载地址:http://www.devstore.cn/code/info/68.html 源码简介 通过集成微客服的SDK和小米推送等常用SDK实现一款仿微信聊天的工具. 源码片段 源码运行截图

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

今年的FIFA世界杯甚是精彩,最近兴致高涨就利用HTML5开发了一个手机端仿微信界面聊天室,该h5聊天室采用750px全新伸缩flex布局,以及使用rem响应式配合fontsize.js,页面弹窗则是使用自己开发的wcPop.js插件:编辑器部分由原先的单一表情新增为动图表情,实现了消息.表情发送 | 大图.视频效果预览 | 仿微信红包.打赏等微交互功能. 案例截图: // ...滚动聊天区底部 function wchat_ToBottom(){ //$(".wc__chatMsg-panel

Android:NineGridLayout — 仿微信朋友圈和QQ空间的九宫格图片展示自定义控件

NineGridLayout 一个仿微信朋友圈和QQ空间的九宫格图片展示自定义控件. GitHub:https://github.com/HMY314/NineGridLayout 一.介绍 1.当只有1张图时,可以自己定制图片宽高,也可以使用默认九宫格的宽高: 2.当只有4张图时,以2*2的方式显示: 3.除以上两种情况下,都是按照3列方式显示,但这时有一些细节: a.如果只有9张图,当然是以3*3的方式显示: b.如果超过9张图,可以设置是否全部显示. 如果设置不完全显示,则按照3*3的方式

Android 高仿微信实时聊天 基于百度云推送

转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38799363 ,本文出自:[张鸿洋的博客] 一直在仿微信界面,今天终于有幸利用百度云推送仿一仿微信聊天了~~~ 首先特别感谢:weidi1989分享的Android之基于百度云推送IM ,大家可以直接下载:省了很多事哈,本例中也使用了weidi的部分代码,凡是@author way的就是weidi1989的代码~~ 1.效果图 核心功能也就上面的两张图了~~~我拿着手机和模拟器

Android仿微信语音聊天界面

有段时间没有看视频了,昨天晚上抽了点空时间,又看了下鸿洋大神的视频教程,又抽时间写了个学习记录.代码和老师讲的基本一样,网上也有很多相同的博客.我只是在AndroidStudio环境下写的. --主界面代码-- public class MainActivity extends Activity { private ListView mListView; private ArrayAdapter<Recorder> mAdapter; private List<Recorder>

腾讯大牛动态教学:Android 仿微信 QQ 图片裁剪,赶紧收藏起来!

前言 在平时开发中,经常需要实现这样的功能,拍照 - 裁剪,相册 - 裁剪.当然,系统也有裁剪的功能,但是由于机型,系统兼容性等问题,在实际开发当中,我们通常会自己进行实现.今天,就让我们一起来看看怎样实现. 这篇博客实现的功能主要有仿微信,QQ 上传图像裁剪功能,包括拍照,从相册选取.裁剪框的样式有圆形,正方形,九宫格. 主要讲解的功能点 使用说明 整体的实现思路 裁剪框的实现 图片缩放的实现,包括放大,缩小,移动,裁剪等 我们先来看看我们实现的效果图 使用说明 有两种调用方式 第一种 第一种