前言:上一篇,我们说了如何实现了RichEdit,但现实中总会将消息发送到服务器保存起来,众所周知,服务器数据库是不可能保存图片的,所以我们要把图片转换成对应的字符保存在服务器,然后客户端在下载到服务器传来的字符以后,将对应的字符转换成图片,下面我讲讲在本地如何实现这个功能,只要这个懂了以后,对于服务器通信的东东难度不大,我就不再另写DEMO了;
例图:
实现功能:在EditText中输入表情和文字,在点击“显示在下面的TextView中”后,将EditText中的内容转换为文本,在下面的TextView中将此文本解析,显示出对应的图片;
这个例子是在上篇例子的基础上修改而来的,我这里只对修改的两个地方做下阐述:
/** * 点击表情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);在上一篇中,我们在实例话String str="img";而这里实例化为了对应的表情图片的名字;这么做有什么用么;这就是SpannableString功能了,当我们用EditText.getText().toString()显示EditText中的字符时,那么对于图片是没有办法显示的,那怎么办,总不能不显示什么东东来替代图片的位置吧,而这里的传进SpannableString的str就是当调用EditText.getText().toString()时替代所要显示的图片的;
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); } }); }在OnCreate()函数里,增加了几句话,如下:
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); } });这就是对“显示在下面TextView中”按钮的实例化和监听函数,这里最重要的是onClick()里的几句话:
第一句: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()函数
这个类里总共有两个函数,其实主要就一个,另一个只是在内部被调用的,先看看上面被调用到的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; }这个没什么实际功能,就是将传进来的字符和正则表达式进行封装,传到dealExpression()这个函数里面去,我们看看这个函数是什么功能;
/** * 对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; } } }1、首先将字符与正则表达式匹配:Matcher matcher = patten.matcher(spannableString);
参考文章:《完整实例实现QQ表情的发送和接收》:http://blog.csdn.net/duancanmeng/article/details/7677144
源码内容:在源码中除了我上面讲的例子的源码外,还有我参考的这篇博客的源码;向博主致敬!因为您让我们这些初接触者少走了弯路,谢谢!
源码地址:http://download.csdn.net/detail/harvic880925/6842393
请大家尊重原创者版权,转载请标明出处:http://blog.csdn.net/harvic880925/article/details/18216491 谢谢!