前言:上一篇,我们说了如何实现了RichEdit,但现实中总会将消息发送到服务器保存起来,众所周知,服务器数据库是不可能保存图片的,所以我们要把图片转换成对应的字符保存在服务器,然后客户端在下载到服务器传来的字符以后,将对应的字符转换成图片,下面我讲讲在本地如何实现这个功能,只要这个懂了以后,对于服务器通信的东东难度不大,我就不再另写DEMO了;
例图:
实现功能:在EditText中输入表情和文字,在点击“显示在下面的TextView中”后,将EditText中的内容转换为文本,在下面的TextView中将此文本解析,显示出对应的图片;
这个例子是在上篇例子的基础上修改而来的,我这里只对修改的两个地方做下阐述:
一、点击表情GRIDVIEW中的某一项的监听器----gridViewFaceItemClickListener
- /**
- * 点击表情GRIDVIEW中的某一项的监听器
- */
- private OnItemClickListener gridViewFaceItemClickListener = new AdapterView.OnItemClickListener() {
- @Override
- public void onItemClick(AdapterView<?> arg0, View view, int position,
- long id) {
- // TODO Auto-generated method stub
- // 首先得到当前用户点击的表情的信息
- Smile smile = smiles.get(position);
- // 得到当前CURSOR位置
- int cursor = ET_content.getSelectionStart();
- Field f;
- try {
- // 根据资源名字得到Resource和对应的Drawable
- f = (Field) R.drawable.class.getDeclaredField(smile.getName());
- int j = f.getInt(R.drawable.class);
- Drawable d = getResources().getDrawable(j);
- d.setBounds(0, 0, 35, 35);// 设置表情图片的显示大小
- // 显示在EditText中
- String str = null;
- int pos = position + 1;
- if (pos < 10) {
- str = "f00" + pos;
- } else if (pos < 100) {
- str = "f0" + pos;
- } else {
- str = "f" + pos;
- }
- SpannableString ss = new SpannableString(str);
- ImageSpan span = new ImageSpan(d, ImageSpan.ALIGN_BOTTOM);
- ss.setSpan(span, 0, str.length(),
- Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
- ET_content.getText().insert(cursor, ss);
- } catch (Exception e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- };
- String str = null;
- int pos = position + 1;
- if (pos < 10) {
- str = "f00" + pos;
- } else if (pos < 100) {
- str = "f0" + pos;
- } else {
- str = "f" + pos;
- }
- SpannableString ss = new SpannableString(str);
二、然后是OnCreate()函数里
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- // 和 各个组件变量初始化
- InitVariable();
- // 初始化GridView,将其与Adapter绑定
- InitGridView();
- //表情显示图片点击监听
- IV_face.setOnClickListener(faceClickListener);
- //监听点击了表情的哪一项
- GV_faceView.setOnItemClickListener(gridViewFaceItemClickListener);
- //EditText点击监听
- ET_content.setOnClickListener(EditContentClickListener);
- Button btn=(Button)findViewById(R.id.getText);
- final TextView tv=(TextView)findViewById(R.id.text);
- btn.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- // TODO Auto-generated method stub
- String str=ET_content.getText().toString();
- String zhengze = "f0[0-9]{2}|f10[0-7]"; // 正则表达式,用来判断消息内是否有表情
- SpannableString spannableString = ExpressionUtil
- .getExpressionString(getApplicationContext(),str, zhengze);
- tv.setText(spannableString);
- }
- });
- }
- Button btn=(Button)findViewById(R.id.getText);
- final TextView tv=(TextView)findViewById(R.id.text);
- btn.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- // TODO Auto-generated method stub
- String str=ET_content.getText().toString();
- String zhengze = "f0[0-9]{2}|f10[0-7]"; // 正则表达式,用来判断消息内是否有表情
- SpannableString spannableString = ExpressionUtil
- .getExpressionString(getApplicationContext(),str, zhengze);
- tv.setText(spannableString);
- }
- });
第一句:String str=ET_content.getText().toString(); 获得当前EditText中的字符;
第二句:String zhengze = "f0[0-9]{2}|f10[0-7]"; 是一个正则表达式,用来判断消息内是否有表情
第三句:SpannableString spannableString = ExpressionUtil.getExpressionString(getApplicationContext(),str, zhengze);这句是一个函数,正是我们下面要讲的,这句的功能是将传进去的字符,经过正则表达式匹配,找到对应字符的图片,最后返回SpannableString对象的实例;
第四句:tv.setText(spannableString);将返回的图文混排的文字设置到TextView中;
下面我们看看getExpressionString()函数
三、字符解析类----ExpressionUtil
这个类里总共有两个函数,其实主要就一个,另一个只是在内部被调用的,先看看上面被调用到的getExpressionString()函数
- /**
- * 得到一个SpanableString对象,通过传入的字符串,并进行正则判断
- * @param context
- * @param str
- * @return
- */
- public static SpannableString getExpressionString(Context context,String str,String zhengze){
- SpannableString spannableString = new SpannableString(str);
- Pattern sinaPatten = Pattern.compile(zhengze, Pattern.CASE_INSENSITIVE); //通过传入的正则表达式来生成一个pattern
- try {
- dealExpression(context,spannableString, sinaPatten, 0);
- } catch (Exception e) {
- Log.e("dealExpression", e.getMessage());
- }
- return spannableString;
- }
- /**
- * 对spanableString进行正则判断,如果符合要求,则以表情图片代替
- * @param context
- * @param spannableString
- * @param patten
- * @param start
- * @throws SecurityException
- * @throws NoSuchFieldException
- * @throws NumberFormatException
- * @throws IllegalArgumentException
- * @throws IllegalAccessException
- */
- public static void dealExpression(Context context,SpannableString spannableString, Pattern patten, int start) throws Exception {
- Matcher matcher = patten.matcher(spannableString);
- while (matcher.find()) {
- String key = matcher.group();//得到整个匹配,也就是文件名,比如f001
- if (matcher.start() < start) {
- continue;
- }
- Field field = R.drawable.class.getDeclaredField(key); //根据得到的名字获得资源
- int resId = Integer.parseInt(field.get(null).toString()); //通过上面匹配得到的字符串来生成图片资源id
- if (resId != 0) {
- Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resId);
- ImageSpan imageSpan = new ImageSpan(bitmap); //通过图片资源id来得到bitmap,用一个ImageSpan来包装
- 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;
- }
- }
- }
2、对于匹配的结果: String key = matcher.group();得到整个匹配,因为我们定义的正则表达式只是匹配的文件句,匹配的结果肯定也就是文件名比如:f001;
3、下面的几句就是根据文件名,得图片资源然后放到spannableString中,替代这个文件名
参考文章:《完整实例实现QQ表情的发送和接收》:http://blog.csdn.net/duancanmeng/article/details/7677144
源码内容:在源码中除了我上面讲的例子的源码外,还有我参考的这篇博客的源码;向博主致敬!因为您让我们这些初接触者少走了弯路,谢谢!