首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >仿微信聊天表情发送

仿微信聊天表情发送

作者头像
xiangzhihong
发布于 2018-01-29 08:17:37
发布于 2018-01-29 08:17:37
8.3K0
举报
文章被收录于专栏:向治洪向治洪

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

其次大致说说原理:

1,首先判断输入的字符,是否包含表情的文字,比如  

 这个表情对应的文件名为 emoji_1.png,它对应的文字描述 : [可爱],如果我们在输出的是输出这么一句话:老婆,我想你了

。  那么我们对应的根本文字就是:老婆,我想你了[可爱]。

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

下面贴上DEMO工程的结构:

再贴上几个重要的类:

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

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

代码语言:java
AI代码解释
复制
package com.example.facedemo;  
 
import java.util.ArrayList;  
import java.util.List;  
 
import android.content.Context;  
import android.graphics.Color;  
import android.graphics.drawable.ColorDrawable;  
import android.support.v4.view.ViewPager;  
import android.support.v4.view.ViewPager.OnPageChangeListener;  
import android.text.SpannableString;  
import android.text.TextUtils;  
import android.util.AttributeSet;  
import android.view.Gravity;  
import android.view.View;  
import android.view.View.OnClickListener;  
import android.view.ViewGroup;  
import android.widget.AdapterView;  
import android.widget.AdapterView.OnItemClickListener;  
import android.widget.EditText;  
import android.widget.GridView;  
import android.widget.ImageView;  
import android.widget.LinearLayout;  
import android.widget.RelativeLayout;  
 
/** 
 *  
 ****************************************** 
 * @author 廖乃波 
 * @文件名称    :  FaceRelativeLayout.java 
 * @创建时间    : 2013-1-27 下午02:34:17 
 * @文件描述    : 带表情的自定义输入框 
 ****************************************** 
 */ 
public class FaceRelativeLayout extends RelativeLayout implements 
        OnItemClickListener, OnClickListener {  
 
 private Context context;  
 
 /** 表情页的监听事件 */ 
 private OnCorpusSelectedListener mListener;  
 
 /** 显示表情页的viewpager */ 
 private ViewPager vp_face;  
 
 /** 表情页界面集合 */ 
 private ArrayList<View> pageViews;  
 
 /** 游标显示布局 */ 
 private LinearLayout layout_point;  
 
 /** 游标点集合 */ 
 private ArrayList<ImageView> pointViews;  
 
 /** 表情集合 */ 
 private List<List<ChatEmoji>> emojis;  
 
 /** 表情区域 */ 
 private View view;  
 
 /** 输入框 */ 
 private EditText et_sendmessage;  
 
 /** 表情数据填充器 */ 
 private List<FaceAdapter> faceAdapters;  
 
 /** 当前表情页 */ 
 private int current = 0;  
 
 public FaceRelativeLayout(Context context) {  
 super(context);  
 this.context = context;  
    }  
 
 public FaceRelativeLayout(Context context, AttributeSet attrs) {  
 super(context, attrs);  
 this.context = context;  
    }  
 
 public FaceRelativeLayout(Context context, AttributeSet attrs, int defStyle) {  
 super(context, attrs, defStyle);  
 this.context = context;  
    }  
 
 public void setOnCorpusSelectedListener(OnCorpusSelectedListener listener) {  
        mListener = listener;  
    }  
 
 /** 
     * 表情选择监听 
     *  
     * @author naibo-liao 
     * @时间: 2013-1-15下午04:32:54 
     */ 
 public interface OnCorpusSelectedListener {  
 
 void onCorpusSelected(ChatEmoji emoji);  
 
 void onCorpusDeleted();  
    }  
 
 @Override 
 protected void onFinishInflate() {  
 super.onFinishInflate();  
        emojis = FaceConversionUtil.getInstace().emojiLists;  
        onCreate();  
    }  
 
 private void onCreate() {  
        Init_View();  
        Init_viewPager();  
        Init_Point();  
        Init_Data();  
    }  
 
 @Override 
 public void onClick(View v) {  
 switch (v.getId()) {  
 case R.id.btn_face:  
 // 隐藏表情选择框 
 if (view.getVisibility() == View.VISIBLE) {  
                view.setVisibility(View.GONE);  
            } else {  
                view.setVisibility(View.VISIBLE);  
            }  
 break;  
 case R.id.et_sendmessage:  
 // 隐藏表情选择框 
 if (view.getVisibility() == View.VISIBLE) {  
                view.setVisibility(View.GONE);  
            }  
 break;  
 
        }  
    }  
 
 /** 
     * 隐藏表情选择框 
     */ 
 public boolean hideFaceView() {  
 // 隐藏表情选择框 
 if (view.getVisibility() == View.VISIBLE) {  
            view.setVisibility(View.GONE);  
 return true;  
        }  
 return false;  
    }  
 
 /** 
     * 初始化控件 
     */ 
 private void Init_View() {  
        vp_face = (ViewPager) findViewById(R.id.vp_contains);  
        et_sendmessage = (EditText) findViewById(R.id.et_sendmessage);  
        layout_point = (LinearLayout) findViewById(R.id.iv_image);  
        et_sendmessage.setOnClickListener(this);  
        findViewById(R.id.btn_face).setOnClickListener(this);  
        view = findViewById(R.id.ll_facechoose);  
 
    }  
 
 /** 
     * 初始化显示表情的viewpager 
     */ 
 private void Init_viewPager() {  
        pageViews = new ArrayList<View>();  
 // 左侧添加空页 
        View nullView1 = new View(context);  
 // 设置透明背景 
        nullView1.setBackgroundColor(Color.TRANSPARENT);  
        pageViews.add(nullView1);  
 
 // 中间添加表情页 
 
        faceAdapters = new ArrayList<FaceAdapter>();  
 for (int i = 0; i < emojis.size(); i++) {  
            GridView view = new GridView(context);  
            FaceAdapter adapter = new FaceAdapter(context, emojis.get(i));  
            view.setAdapter(adapter);  
            faceAdapters.add(adapter);  
            view.setOnItemClickListener(this);  
            view.setNumColumns(7);  
            view.setBackgroundColor(Color.TRANSPARENT);  
            view.setHorizontalSpacing(1);  
            view.setVerticalSpacing(1);  
            view.setStretchMode(GridView.STRETCH_COLUMN_WIDTH);  
            view.setCacheColorHint(0);  
            view.setPadding(5, 0, 5, 0);  
            view.setSelector(new ColorDrawable(Color.TRANSPARENT));  
            view.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,  
                    LayoutParams.WRAP_CONTENT));  
            view.setGravity(Gravity.CENTER);  
            pageViews.add(view);  
        }  
 
 // 右侧添加空页面 
        View nullView2 = new View(context);  
 // 设置透明背景 
        nullView2.setBackgroundColor(Color.TRANSPARENT);  
        pageViews.add(nullView2);  
    }  
 
 /** 
     * 初始化游标 
     */ 
 private void Init_Point() {  
 
        pointViews = new ArrayList<ImageView>();  
        ImageView imageView;  
 for (int i = 0; i < pageViews.size(); i++) {  
            imageView = new ImageView(context);  
            imageView.setBackgroundResource(R.drawable.d1);  
            LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(  
 new ViewGroup.LayoutParams(LayoutParams.WRAP_CONTENT,  
                            LayoutParams.WRAP_CONTENT));  
            layoutParams.leftMargin = 10;  
            layoutParams.rightMargin = 10;  
            layoutParams.width = 8;  
            layoutParams.height = 8;  
            layout_point.addView(imageView, layoutParams);  
 if (i == 0 || i == pageViews.size() - 1) {  
                imageView.setVisibility(View.GONE);  
            }  
 if (i == 1) {  
                imageView.setBackgroundResource(R.drawable.d2);  
            }  
            pointViews.add(imageView);  
 
        }  
    }  
 
 /** 
     * 填充数据 
     */ 
 private void Init_Data() {  
        vp_face.setAdapter(new ViewPagerAdapter(pageViews));  
 
        vp_face.setCurrentItem(1);  
        current = 0;  
        vp_face.setOnPageChangeListener(new OnPageChangeListener() {  
 
 @Override 
 public void onPageSelected(int arg0) {  
                current = arg0 - 1;  
 // 描绘分页点 
                draw_Point(arg0);  
 // 如果是第一屏或者是最后一屏禁止滑动,其实这里实现的是如果滑动的是第一屏则跳转至第二屏,如果是最后一屏则跳转到倒数第二屏. 
 if (arg0 == pointViews.size() - 1 || arg0 == 0) {  
 if (arg0 == 0) {  
                        vp_face.setCurrentItem(arg0 + 1);// 第二屏 会再次实现该回调方法实现跳转. 
                        pointViews.get(1).setBackgroundResource(R.drawable.d2);  
                    } else {  
                        vp_face.setCurrentItem(arg0 - 1);// 倒数第二屏 
                        pointViews.get(arg0 - 1).setBackgroundResource(  
                                R.drawable.d2);  
                    }  
                }  
            }  
 
 @Override 
 public void onPageScrolled(int arg0, float arg1, int arg2) {  
 
            }  
 
 @Override 
 public void onPageScrollStateChanged(int arg0) {  
 
            }  
        });  
 
    }  
 
 /** 
     * 绘制游标背景 
     */ 
 public void draw_Point(int index) {  
 for (int i = 1; i < pointViews.size(); i++) {  
 if (index == i) {  
                pointViews.get(i).setBackgroundResource(R.drawable.d2);  
            } else {  
                pointViews.get(i).setBackgroundResource(R.drawable.d1);  
            }  
        }  
    }  
 
 @Override 
 public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {  
        ChatEmoji emoji = (ChatEmoji) faceAdapters.get(current).getItem(arg2);  
 if (emoji.getId() == R.drawable.face_del_icon) {  
 int selection = et_sendmessage.getSelectionStart();  
            String text = et_sendmessage.getText().toString();  
 if (selection > 0) {  
                String text2 = text.substring(selection - 1);  
 if ("]".equals(text2)) {  
 int start = text.lastIndexOf("[");  
 int end = selection;  
                    et_sendmessage.getText().delete(start, end);  
 return;  
                }  
                et_sendmessage.getText().delete(selection - 1, selection);  
            }  
        }  
 if (!TextUtils.isEmpty(emoji.getCharacter())) {  
 if (mListener != null)  
                mListener.onCorpusSelected(emoji);  
            SpannableString spannableString = FaceConversionUtil.getInstace()  
                    .addFace(getContext(), emoji.getId(), emoji.getCharacter());  
            et_sendmessage.append(spannableString);  
        }  
 
    }  
}  

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

代码语言:java
AI代码解释
复制
package com.example.facedemo;  
 
import android.content.Context;  
 
import android.text.SpannableString;  
import android.view.LayoutInflater;  
import android.view.View;  
import android.view.ViewGroup;  
 
import android.widget.BaseAdapter;  
import android.widget.TextView;  
 
import java.util.List;  
 
/** 
 *  
 ****************************************** 
 * @author 廖乃波 
 * @文件名称    :  ChatMsgAdapter.java 
 * @创建时间    : 2013-1-27 下午02:33:16 
 * @文件描述    : 消息数据填充起 
 ****************************************** 
 */ 
public class ChatMsgAdapter extends BaseAdapter {  
 
 public static interface IMsgViewType {  
 int IMVT_COM_MSG = 0;  
 int IMVT_TO_MSG = 1;  
    }  
 
 private List<ChatMsgEntity> coll;  
 private LayoutInflater mInflater;  
 private Context context;  
 public ChatMsgAdapter(Context context, List<ChatMsgEntity> coll) {  
 this.coll = coll;  
        mInflater = LayoutInflater.from(context);  
 this.context = context;  
    }  
 
 public int getCount() {  
 return coll.size();  
    }  
 
 public Object getItem(int position) {  
 return coll.get(position);  
    }  
 
 public long getItemId(int position) {  
 return position;  
    }  
 
 public int getItemViewType(int position) {  
        ChatMsgEntity entity = coll.get(position);  
 
 if (entity.getMsgType()) {  
 return IMsgViewType.IMVT_COM_MSG;  
        } else {  
 return IMsgViewType.IMVT_TO_MSG;  
        }  
 
    }  
 
 public int getViewTypeCount() {  
 return 2;  
    }  
 
 public View getView(int position, View convertView, ViewGroup parent) {  
 
        ChatMsgEntity entity = coll.get(position);  
 boolean isComMsg = entity.getMsgType();  
 
        ViewHolder viewHolder = null;  
 if (convertView == null) {  
 if (isComMsg) {  
                convertView = mInflater.inflate(  
                        R.layout.chatting_item_msg_text_left, null);  
            } else {  
                convertView = mInflater.inflate(  
                        R.layout.chatting_item_msg_text_right, null);  
            }  
 
            viewHolder = new ViewHolder();  
            viewHolder.tvSendTime = (TextView) convertView  
                    .findViewById(R.id.tv_sendtime);  
            viewHolder.tvContent = (TextView) convertView  
                    .findViewById(R.id.tv_chatcontent);  
            viewHolder.isComMsg = isComMsg;  
 
            convertView.setTag(viewHolder);  
        } else {  
            viewHolder = (ViewHolder) convertView.getTag();  
        }  
 
        viewHolder.tvSendTime.setText(entity.getDate());  
        SpannableString spannableString = FaceConversionUtil.getInstace().getExpressionString(context, entity.getText());  
        viewHolder.tvContent.setText(spannableString);  
 
 return convertView;  
    }  
 
 class ViewHolder {  
 public TextView tvSendTime;  
 public TextView tvContent;  
 public boolean isComMsg = true;  
    }  
 
}  

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

代码语言:java
AI代码解释
复制
package com.example.facedemo;  
 
import java.io.BufferedReader;  
import java.io.IOException;  
import java.io.InputStream;  
import java.io.InputStreamReader;  
import java.util.ArrayList;  
import java.util.List;  
 
import android.content.Context;  
 
/** 
 *  
 ****************************************** 
 * @author 廖乃波 
 * @文件名称    :  FileUtils.java 
 * @创建时间    : 2013-1-27 下午02:35:09 
 * @文件描述    : 文件工具类 
 ****************************************** 
 */ 
public class FileUtils {  
 /** 
     * 读取表情配置文件 
     *  
     * @param context 
     * @return 
     */ 
 public static List<String> getEmojiFile(Context context) {  
 try {  
            List<String> list = new ArrayList<String>();  
            InputStream in = context.getResources().getAssets().open("emoji");  
            BufferedReader br = new BufferedReader(new InputStreamReader(in,  
 "UTF-8"));  
            String str = null;  
 while ((str = br.readLine()) != null) {  
                list.add(str);  
            }  
 
 return list;  
        } catch (IOException e) {  
            e.printStackTrace();  
        }  
 return null;  
    }  
}  

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

代码语言:java
AI代码解释
复制
package com.example.facedemo;  
 
import java.util.List;  
 
import android.support.v4.view.PagerAdapter;  
import android.support.v4.view.ViewPager;  
import android.view.View;  
/** 
 *  
 ****************************************** 
 * @author 廖乃波 
 * @文件名称    :  ViewPagerAdapter.java 
 * @创建时间    : 2013-1-27 下午02:35:27 
 * @文件描述    : ViewPager 数据填充器,切记做其他操作!!!只填充View!!!! 
 ****************************************** 
 */ 
public class ViewPagerAdapter extends PagerAdapter {  
 
 private List<View> pageViews;  
 
 public ViewPagerAdapter(List<View> pageViews) {  
 super();  
 this.pageViews=pageViews;  
    }  
 
 // 显示数目 
 @Override 
 public int getCount() {  
 return pageViews.size();  
    }  
 
 @Override 
 public boolean isViewFromObject(View arg0, Object arg1) {  
 return arg0 == arg1;  
    }  
 
 @Override 
 public int getItemPosition(Object object) {  
 return super.getItemPosition(object);  
    }  
 
 @Override 
 public void destroyItem(View arg0, int arg1, Object arg2) {  
        ((ViewPager)arg0).removeView(pageViews.get(arg1));  
    }  
 
 /*** 
     * 获取每一个item�?类于listview中的getview 
     */ 
 @Override 
 public Object instantiateItem(View arg0, int arg1) {  
        ((ViewPager)arg0).addView(pageViews.get(arg1));  
 return pageViews.get(arg1);  
    }  
}  

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

代码语言:java
AI代码解释
复制
emoji_1.png,[可爱]  
emoji_2.png,[笑脸]  
emoji_3.png,[]  
emoji_4.png,[生气]  
emoji_5.png,[鬼脸]  
emoji_6.png,[花心]  
emoji_7.png,[害怕]  
emoji_8.png,[我汗]  
emoji_9.png,[尴尬]  
emoji_10.png,[哼哼]  
emoji_11.png,[忧郁]  
emoji_12.png,[呲牙]  
emoji_13.png,[媚眼]  
emoji_14.png,[]  
emoji_15.png,[苦逼]  
emoji_16.png,[瞌睡]  
emoji_17.png,[哎呀]  
emoji_18.png,[刺瞎]  
emoji_19.png,[]  
emoji_20.png,[激动]  
emoji_21.png,[难过]  
emoji_22.png,[害羞]  
emoji_23.png,[高兴]  
emoji_24.png,[愤怒]  
emoji_25.png,[]  
emoji_26.png,[飞吻]  
emoji_27.png,[得意]  
emoji_28.png,[惊恐]  
emoji_29.png,[口罩]  
emoji_30.png,[惊讶]  
emoji_31.png,[委屈]  
emoji_32.png,[生病]  
emoji_33.png,[红心]  
emoji_34.png,[心碎]  
emoji_35.png,[玫瑰]  
emoji_36.png,[]  
emoji_37.png,[外星人]  
emoji_38.png,[金牛座]  
emoji_39.png,[双子座]  
emoji_40.png,[巨蟹座]  
emoji_41.png,[狮子座]  
emoji_42.png,[处女座]  
emoji_43.png,[天平座]  
emoji_44.png,[天蝎座]  
emoji_45.png,[射手座]  
emoji_46.png,[摩羯座]  
emoji_47.png,[水瓶座]  
emoji_48.png,[白羊座]  
emoji_49.png,[双鱼座]  
emoji_50.png,[星座]  
emoji_51.png,[男孩]  
emoji_52.png,[女孩]  
emoji_53.png,[嘴唇]  
emoji_54.png,[爸爸]  
emoji_55.png,[妈妈]  
emoji_56.png,[衣服]  
emoji_57.png,[皮鞋]  
emoji_58.png,[照相]  
emoji_59.png,[电话]  
emoji_60.png,[石头]  
emoji_61.png,[胜利]  
emoji_62.png,[禁止]  
emoji_63.png,[滑雪]  
emoji_64.png,[高尔夫]  
emoji_65.png,[网球]  
emoji_66.png,[棒球]  
emoji_67.png,[冲浪]  
emoji_68.png,[足球]  
emoji_69.png,[小鱼]  
emoji_70.png,[问号]  
emoji_71.png,[叹号]  
emoji_179.png,[]  
emoji_180.png,[写字]  
emoji_181.png,[衬衫]  
emoji_182.png,[小花]  
emoji_183.png,[郁金香]  
emoji_184.png,[向日葵]  
emoji_185.png,[鲜花]  
emoji_186.png,[椰树]  
emoji_187.png,[仙人掌]  
emoji_188.png,[气球]  
emoji_189.png,[炸弹]  
emoji_190.png,[喝彩]  
emoji_191.png,[剪子]  
emoji_192.png,[蝴蝶结]  
emoji_193.png,[机密]  
emoji_194.png,[铃声]  
emoji_195.png,[女帽]  
emoji_196.png,[裙子]  
emoji_197.png,[理发店]  
emoji_198.png,[和服]  
emoji_199.png,[比基尼]  
emoji_200.png,[拎包]  
emoji_201.png,[拍摄]  
emoji_202.png,[铃铛]  
emoji_203.png,[音乐]  
emoji_204.png,[心星]  
emoji_205.png,[粉心]  
emoji_206.png,[丘比特]  
emoji_207.png,[吹气]  
emoji_208.png,[口水]  
emoji_209.png,[]  
emoji_210.png,[]  
emoji_211.png,[绿茶]  
emoji_212.png,[面包]  
emoji_213.png,[面条]  
emoji_214.png,[咖喱饭]  
emoji_215.png,[饭团]  
emoji_216.png,[麻辣烫]  
emoji_217.png,[寿司]  
emoji_218.png,[苹果]  
emoji_219.png,[橙子]  
emoji_220.png,[草莓]  
emoji_221.png,[西瓜]  
emoji_222.png,[柿子]  
emoji_223.png,[眼睛]  
emoji_224.png,[好的]  

忘了布局文件,哇哈哈

代码语言:html
AI代码解释
复制
<?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> 

 源码

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2014-04-06 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
漫画:什么是时间复杂度?
场景1. 给小灰一条长10寸的面包,小灰每3天吃掉1寸,那么吃掉整个面包需要几天?
用户1564362
2019/07/04
4320
算法复杂度(二)
[ 来自360百科 ]算法在编写成可执行程序后,运行时所需要的资源,资源包括时间资源和内存资源。应用于数学和计算机导论。同一问题可用不同算法解决,而一个算法的质量优劣将影响到算法乃至程序的效率。算法分析的目的在于选择合适算法和改进算法。一个算法的评价主要从时间复杂度和空间复杂度来考虑。下面就时间复杂度和空间复杂度做出解释。
花狗Fdog
2020/10/28
6130
算法复杂度(二)
【数据结构和算法的概述】-01
数据结构是计算机存储、组织数据的方式。数据结构是指相互之间存在一种或多种特定关系的数据元素的集合。通常情况下,精心选择的数据结构可以带来更高的运行或者存储效率。数据结构往往同高效的检索算法和索引技术有关。
跟着飞哥学编程
2023/04/03
7430
【数据结构和算法的概述】-01
数据结构与算法(一)| 时间复杂度与空间复杂度
外层每执行一次,内层执行100次。总的执行次数为 100 * 100。即 n 的平方。此时 大O 为 O(n^2)
Mervyn
2020/07/21
3770
算法(一)时间复杂度
前言 算法很重要,但是一般情况下做移动开发并不经常用到,所以很多同学早就将算法打了个大礼包送还给了老师了,况且很多同学并没有学习过算法。这个系列就让对算法头疼的同学能快速的掌握基本的算法。过年放假阶段玩了会游戏NBA2K17的生涯模式,没有比赛的日子也都是训练,而且这些训练都是自发的,没有人逼你,从早上练到晚上,属性也不涨,但是如果日积月累,不训练和训练的人的属性值就会产生较大差距。这个突然让我意识到了现实世界,要想成为一个球星(技术大牛)那就需要日积月累的刻意训练,索性放下游戏,接着写文章吧。 1.算法的
用户1269200
2018/02/01
8780
算法(一)时间复杂度
解惑3:时间频度,算法时间复杂度[通俗易懂]
要理解时间复杂度,需要先理解时间频度,而时间频度简单的说,就是算法中语句的执行次数。
全栈程序员站长
2022/09/23
8670
解惑3:时间频度,算法时间复杂度[通俗易懂]
算法—时间复杂度[通俗易懂]
时间和空间都是计算机资源的重要体现,而算法的复杂性就是体现在运行该算法时的计算机所需的资源多少;
全栈程序员站长
2022/08/27
3.3K0
算法—时间复杂度[通俗易懂]
时间复杂度
很多人包括我自己都有一个疑问,就是现在的计算机的硬件性能已经很强大了,所以对于性能或者说时间复杂度上还用关心吗,答案是需要的。 比如有这样一个例子,在一台很久的机器和一台处理性能高100倍的新机器,旧机器执行算法A时间复杂度为O(n),新机器执行算法B的时间复杂度为O(n2)。下面表格做下对比,因为性能差100倍,所以旧机器时间*100
OPice
2021/09/07
6630
算法时间复杂度计算方式
【对于一个给定的算法,通常要评估其正确性和运行效率的高低。算法的正确性评估不在本文范围之内,本文主要讨论从算法的时间复杂度特性去评估算法的优劣。】
全栈程序员站长
2022/08/28
5470
算法时间复杂度计算方式
数据结构与算法系列之时间复杂度
上一篇《数据结构和算法》中我介绍了数据结构的基本概念,也介绍了数据结构一般可以分为逻辑结构和物理结构。逻辑结构分为集合结构、线性结构、树形结构和图形结构。物理结构分为顺序存储结构和链式存储结构。并且也介绍了这些结构的特点。然后,又介绍了算法的概念和算法的5个基本特性,分别是输入、输出、有穷性、确定性和可行性。最后说阐述了一个好的算法需要遵守正确性、可读性、健壮性、时间效率高和存储量低。其实,实现效率和存储量就是时间复杂度和空间复杂度。本篇我们就围绕这两个"复杂度"展开说明。在真正的开发中,时间复杂度尤为重要,空间复杂度我们不做太多说明。
VV木公子
2018/06/05
5.6K0
数据结构与算法系列之时间复杂度
【久远讲算法①】什么是时间复杂度
小学数学课上,你是不是可以用 3+3+3 或者 3*3 来解决三个三相加这个问题,虽然算的结果都是9,但是中间我们用的方法是不一样的。
AI悦创
2021/10/10
3660
【久远讲算法①】什么是时间复杂度
排序算法
排序也称排序算法(Sort Algorithm),排序是将一组数据,依指定的顺序进行排列的过程。
用户9615083
2022/12/30
3010
排序算法
【数据结构】算法的时间复杂度
上一小节我们讲到,比较两个算法的优劣最重要的比较方式就是拿算法的时间复杂度来做比较.这节我们就来系统的学习一下算法的时间复杂度:
修修修也
2024/04/01
1860
【数据结构】算法的时间复杂度
算法时间复杂度
很多程序员,做了很长时间的编程工作却始终都弄不明白算法的时间复杂度的估算,这是很可悲的一件事情。因为弄不清楚,所以也就从不深究自己写的代码是否效率底下,是不是可以通过优化,让计算机更加快速高效。所以在我最近自学看完算法的时间复杂度这个章节之后,我决定写一篇文章回顾,加深记忆,帮助理解。
Originalee
2018/08/30
9020
算法的时间复杂度和空间复杂度-总结[通俗易懂]
通常,对于一个给定的算法,我们要做 两项分析。第一是从数学上证明算法的正确性,这一步主要用到形式化证明的方法及相关推理模式,如循环不变式、数学归纳法等。而在证明算法是正确的基础上,第二部就是分析算法的时间复杂度。算法的时间复杂度反映了程序执行时间随输入规模增长而增长的量级,在很大程度上能很好反映出算法的优劣与否。因此,作为程序员,掌握基本的算法时间复杂度分析方法是很有必要的。 算法执行时间需通过依据该算法编制的程序在计算机上运行时所消耗的时间来度量。而度量一个程序的执行时间通常有两种方法。
全栈程序员站长
2022/08/27
1.6K0
时间复杂度和空间复杂度 如何计算出来_代码时间复杂度和空间复杂度
在进行算法分析时,语句总的执行次数T(n)是关于问题规模n的函数,进而分析T(n)随n的变化情况并确定T(n)的数量级。算法的时间复杂度,也就是算法的时间量度,记作:T(n}=0(f(n))。它表示随问题规模n的增大,算法执行时间的埔长率和 f(n)的埔长率相同,称作算法的渐近时间复杂度,简称为时间复杂度。其中f( n)是问题规横n的某个函数。
全栈程序员站长
2022/11/17
7060
时间复杂度和空间复杂度 如何计算出来_代码时间复杂度和空间复杂度
【进阶之路】算法的时间复杂度与空间复杂度
.markdown-body{word-break:break-word;line-height:1.75;font-weight:400;font-size:15px;overflow-x:hidden;color:#333}.markdown-body h1,.markdown-body h2,.markdown-body h3,.markdown-body h4,.markdown-body h5,.markdown-body h6{line-height:1.5;margin-top:35px;margin-bottom:10px;padding-bottom:5px}.markdown-body h1{font-size:30px;margin-bottom:5px}.markdown-body h2{padding-bottom:12px;font-size:24px;border-bottom:1px solid #ececec}.markdown-body h3{font-size:18px;padding-bottom:0}.markdown-body h4{font-size:16px}.markdown-body h5{font-size:15px}.markdown-body h6{margin-top:5px}.markdown-body p{line-height:inherit;margin-top:22px;margin-bottom:22px}.markdown-body img{max-width:100%}.markdown-body hr{border:none;border-top:1px solid #ddd;margin-top:32px;margin-bottom:32px}.markdown-body code{word-break:break-word;border-radius:2px;overflow-x:auto;background-color:#fff5f5;color:#ff502c;font-size:.87em;padding:.065em .4em}.markdown-body code,.markdown-body pre{font-family:Menlo,Monaco,Consolas,Courier New,monospace}.markdown-body pre{overflow:auto;position:relative;line-height:1.75}.markdown-body pre>code{font-size:12px;padding:15px 12px;margin:0;word-break:normal;display:block;overflow-x:auto;color:#333;background:#f8f8f8}.markdown-body a{text-decoration:none;color:#0269c8;border-bottom:1px solid #d1e9ff}.markdown-body a:active,.markdown-body a:hover{color:#275b8c}.markdown-body table{display:inline-block!important;font-size:12px;width:auto;max-width:100%;overflow:auto;border:1px solid #f6f6f6}.markdown-body thead{background:#f6f6f6;color:#000;text-align:left}.markdown-body tr:nth-child(2n){background-color:#fcfcfc}.markdown-body td,.markdown-body th{padding:12px 7px;line-height:24px}.markdown-body td{min-width:120px}.markdown-body blockquote{color:#666;padding:1px 23px;margin:22px 0;border-left:4px solid #cbcbcb;background-color:#f8f8f8}.markdown-body blockquote:after{display:block;content:""}.markdown-body blockquote>p{margin:10px 0}.markdown-body ol,.markdown-body ul{padding-left:28px}.markdown-body ol li,.markdown-body
南橘
2021/04/02
9050
【进阶之路】算法的时间复杂度与空间复杂度
数据结构算法的时间复杂度_数据结构中排序的时间复杂度
大家好,我是架构君,一个会写代码吟诗的架构师。今天说一说数据结构算法的时间复杂度_数据结构中排序的时间复杂度,希望能够帮助大家进步!!!
Java架构师必看
2022/08/14
1.2K0
数据结构算法的时间复杂度_数据结构中排序的时间复杂度
数据结构之时间复杂度和空间复杂度
我们都知道算法是处理数据的方法,那么如何衡量一个算法的好坏呢?(即,判断该算法的效率如何) 由于算法在编写成可执行程序后,运行会消耗时间资源和空间(内存)资源,因此衡量一个算法的好坏一般通过时间和空间两个维度进行衡量。即,时间复杂度和空间复杂度。
摘星
2023/04/28
3120
数据结构之时间复杂度和空间复杂度
常见算法时间复杂度
同一问题可用不同算法解决,而一个算法的质量优劣将影响到算法乃至程序的效率。算法分析的目的在于选择合适算法和改进算法。一个算法的评价主要从时间复杂度和空间复杂度来考虑。
全栈程序员站长
2022/08/28
6440
推荐阅读
相关推荐
漫画:什么是时间复杂度?
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档