android仿QQ聊天,带表情,可翻页,带翻页拖动缓冲
|
admin
2013年2月25日 17:48
本文热度 5855
|
如题,这是公司项目的一个功能模块,先上个效果图:
其次大致说说原理:
1,首先判断输入的字符,是否包含表情的文字,比如 这个表情对应的文件名为 emoji_1.png,它对应的文字描述 : [可爱],如果我们在输出的是输出这么一句话:老婆,我想你了。 那么我们对应的根本文字就是:老婆,我想你了[可爱]。
2,具体的转换过程就是用正则表达式比配文字中是否含有[xxx]这类的文字,如果有,那么我们就根据拿到的[xxx]找到它对应的资源文件id,当然这其中有一个关系表,看你怎么处理这个关系了。最后将其用SpannableString替换成文字,表面上显示有图片,其实TextView里的text依然是:老婆,我想你了[可爱]。这个过程明白么?
下面贴上DEMO工程的结构:
再贴上几个重要的类:
- 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;
-
-
-
-
-
-
-
-
-
-
- public class FaceConversionUtil {
-
-
- private int pageSize = 20;
-
- private static FaceConversionUtil mFaceConversionUtil;
-
-
- private HashMap emojiMap = new HashMap();
-
-
- private List emojis = new ArrayList();
-
-
- public List
> emojiLists = new ArrayList>();
-
- private FaceConversionUtil() {
-
- }
-
- public static FaceConversionUtil getInstace() {
- if (mFaceConversionUtil == null) {
- mFaceConversionUtil = new FaceConversionUtil();
- }
- return mFaceConversionUtil;
- }
-
-
-
-
-
-
-
-
- public SpannableString getExpressionString(Context context, String str) {
- SpannableString spannableString = new SpannableString(str);
-
- String zhengze = "\\[[^\\]]+\\]";
-
- Pattern sinaPatten = Pattern.compile(zhengze, Pattern.CASE_INSENSITIVE);
- try {
- dealExpression(context, spannableString, sinaPatten, 0);
- } catch (Exception e) {
- Log.e("dealExpression", e.getMessage());
- }
- return spannableString;
- }
-
-
-
-
-
-
-
-
-
- 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;
- }
-
-
-
-
-
-
-
-
-
-
- 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();
-
- if (matcher.start() < start) {
- continue;
- }
- String value = emojiMap.get(key);
- if (TextUtils.isEmpty(value)) {
- continue;
- }
- int resId = context.getResources().getIdentifier(value, "drawable",
- context.getPackageName());
-
-
-
- if (resId != 0) {
- Bitmap bitmap = BitmapFactory.decodeResource(
- context.getResources(), resId);
- bitmap = Bitmap.createScaledBitmap(bitmap, 50, 50, true);
-
- 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);
- }
-
-
-
-
-
-
- private void ParseData(List 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();
- }
- }
-
-
-
-
-
-
-
- private List getData(int page) {
- int startIndex = page * pageSize;
- int endIndex = startIndex + pageSize;
-
- if (endIndex > emojis.size()) {
- endIndex = emojis.size();
- }
-
- List list = new ArrayList();
- 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]
- 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;
-
-
-
-
-
-
-
-
-
-
- public class FaceRelativeLayout extends RelativeLayout implements
- OnItemClickListener, OnClickListener {
-
- private Context context;
-
-
- private OnCorpusSelectedListener mListener;
-
-
- private ViewPager vp_face;
-
-
- private ArrayList pageViews;
-
-
- private LinearLayout layout_point;
-
-
- private ArrayList pointViews;
-
-
- private List
> emojis;
-
-
- private View view;
-
-
- private EditText et_sendmessage;
-
-
- private List 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;
- }
-
-
-
-
-
-
-
- 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);
-
- }
-
-
-
-
- private void Init_viewPager() {
- pageViews = new ArrayList();
-
- View nullView1 = new View(context);
-
- nullView1.setBackgroundColor(Color.TRANSPARENT);
- pageViews.add(nullView1);
-
-
-
- faceAdapters = new ArrayList();
- 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;
- 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]
最开始要读取的表情配置文件
[java]
- 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;
-
-
-
-
-
-
-
-
-
-
- public class FileUtils {
-
-
-
-
-
-
- public static List getEmojiFile(Context context) {
- try {
- List list = new ArrayList();
- 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;
- }
- }
下边这个是表情翻页的数据填充,用的是viewpager,每一页填充的是一个gridview
- package com.example.facedemo;
-
- import java.util.List;
-
- import android.support.v4.view.PagerAdapter;
- import android.support.v4.view.ViewPager;
- import android.view.View;
-
-
-
-
-
-
-
-
-
- public class ViewPagerAdapter extends PagerAdapter {
-
- private List pageViews;
-
- public ViewPagerAdapter(List 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));
- }
-
-
-
-
- @Override
- public Object instantiateItem(View arg0, int arg1) {
- ((ViewPager)arg0).addView(pageViews.get(arg1));
- return pageViews.get(arg1);
- }
- }
最后呢,是表情的配置文件,你想怎么搞都行,我就这么搞的
[java]
- 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,[好的]
忘了布局文件,哇哈哈
- <?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>
该文章在 2013/2/25 17:48:16 编辑过
|
|