Android编写简单的聊天室应用
作者:楊先生 发布时间:2023-12-19 10:49:38
标签:Android,聊天室
最近写了一个简单的聊天室应用,可以发送表情,更改头像这些功能。主要技术点就是怎样把表情图片放到textview等Ui控件中展示。这里废话不多说,下面是效果图:
这里主要讲下怎样把文本替换到表情,先说下思路,首先我们的图片是保存在本地资源目录drawable中而所有的资源文件都是R这个类来管理,所以我们可以利用正则表达式找出图片id包装成ImageSpan然后把ImageSpan放到SpannableString中,最后把SpannableString放入edittext中,下面是源码:
package com.coreandroid.util;
import java.lang.reflect.Field;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import android.content.Context;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.style.ImageSpan;
import android.util.Log;
import com.coreandroid.chart.R;
public class ExpressionUtil {
/**
* 对spanableString进行正则判断,如果符合要求,则以表情图片代替
*
* @param context
* @param spannableString
* @param patten
* @param start
*/
public static void matchExpression(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;
}
Field field = R.drawable.class.getDeclaredField(key);
int resId = field.getInt(null); // 通过上面匹配得到的字符串来生成图片资源id
if (resId != 0) {
ImageSpan imageSpan = new ImageSpan(context, resId); // 通过图片资源id来得到bitmap,用一个ImageSpan来包装
int end = matcher.start() + key.length(); // 计算该图片名字的长度,也就是要替换的字符串的长度
spannableString.setSpan(imageSpan, matcher.start(), end,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); // 将该图片替换字符串中规定的位置中
if (end < spannableString.length()) { // 如果整个字符串还未验证完,则继续。。
matchExpression(context, spannableString, patten, end);
}
break;
}
}
}
/**
* 得到一个SpanableString对象,通过传入的字符串,并进行正则判断
*
* @param context
* @param str
* @return SpannableString
*/
public static SpannableString getExpressionString(Context context,
String str, String zhengze) {
SpannableString spannableString = new SpannableString(str);
Pattern sinaPatten = Pattern.compile(zhengze); // 通过传入的正则表达式来生成一个pattern
try {
matchExpression(context, spannableString, sinaPatten, 0);
} catch (Exception e) {
Log.e("dealExpression", e.getMessage());
}
return spannableString;
}
}
下面是聊天记录列表的adapter,这里主要是动态的改变每个Item的布局来区分是自己还是他人的发言,具体源码如下:
package com.coreandroid.adapter;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import android.content.Context;
import android.text.SpannableString;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.coreandroid.chart.R;
import com.coreandroid.entity.MessageInfo;
import com.coreandroid.util.CommonUtils;
import com.coreandroid.util.ExpressionUtil;
public class ChartListAdapter extends BaseAdapter {
private Context context;
private LayoutInflater inflater;
private List<MessageInfo> data;
private DateFormat df;
public ChartListAdapter(Context context, List<MessageInfo> data) {
super();
this.context = context;
inflater = LayoutInflater.from(context);
this.data = data;
df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
}
@Override
public int getCount() {
return data.size();
}
@Override
public Object getItem(int position) {
return data.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
if (convertView == null) {
convertView = inflater.inflate(R.layout.chart_list_item, null);
holder = new ViewHolder(convertView);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.setData((MessageInfo) getItem(position));
return convertView;
}
private class ViewHolder {
private ImageView image;
private TextView text;
private TextView title;
private RelativeLayout rl;
public ViewHolder(View convertView) {
image = (ImageView) convertView
.findViewById(R.id.chart_list_item_headicon);
text = (TextView) convertView
.findViewById(R.id.chart_list_item_message);
title = (TextView) convertView
.findViewById(R.id.chart_list_item_title);
rl = (RelativeLayout) convertView
.findViewById(R.id.rl_chart_list_bottom);
}
public void setData(MessageInfo msg) {
RelativeLayout.LayoutParams rl_tv_msg_left = (RelativeLayout.LayoutParams) text
.getLayoutParams();
RelativeLayout.LayoutParams rl_iv_headicon_left = (RelativeLayout.LayoutParams) image
.getLayoutParams();
RelativeLayout.LayoutParams rl_tv_title = (RelativeLayout.LayoutParams) title
.getLayoutParams();
RelativeLayout.LayoutParams rl_buttom = (RelativeLayout.LayoutParams) rl
.getLayoutParams();
if (!CommonUtils.getDeviceId().equalsIgnoreCase(msg.getUsermac())) {
// 根据本地的mac地址来判断该条信息是属于本人所说还是对方所说
// 如果是自己说的,则显示在右边;如果是对方所说,则显示在左边
rl_buttom.addRule(RelativeLayout.ALIGN_PARENT_TOP);
rl_tv_title.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
rl_tv_title.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
rl_tv_title.addRule(RelativeLayout.BELOW,
R.id.rl_chart_list_bottom);
rl_iv_headicon_left.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
rl_iv_headicon_left.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
rl_tv_msg_left.addRule(RelativeLayout.RIGHT_OF,
R.id.chart_list_item_headicon);
text.setBackgroundResource(R.drawable.incoming);
String titleStr = msg.getUsermac() + "-"
+ df.format(new Date());
title.setText(titleStr);
} else {
rl_buttom.addRule(RelativeLayout.ALIGN_PARENT_TOP);
rl_tv_title.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
rl_tv_title.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
rl_tv_title.addRule(RelativeLayout.BELOW,
R.id.rl_chart_list_bottom);
rl_iv_headicon_left.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
rl_iv_headicon_left.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
rl_tv_msg_left.addRule(RelativeLayout.LEFT_OF,
R.id.chart_list_item_headicon);
text.setBackgroundResource(R.drawable.outgoing);
String titleStr = df.format(new Date()) + "-"
+ msg.getUsermac();
title.setText(titleStr);
}
if (!TextUtils.isEmpty(msg.getHeadImage())) {
image.setImageBitmap(CommonUtils.strConvertBitmap(msg
.getHeadImage())); // 设置头像
} else {
image.setImageResource(R.drawable.im);
}
String str = msg.getMessage(); // 消息具体内容
try {
SpannableString spannableString = ExpressionUtil
.getExpressionString(context, str, CommonUtils.PATTERN);
text.setText(spannableString);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
源码下载:Android聊天室应用


猜你喜欢
- 0.背景简介微软在 .NET 框架中提供了多种实用的线程同步手段,其中包括 monitor 类及 reader-writer锁。
- 1.线程状态(生命周期)一个线程在给定的时间点只能处于一种状态。线程可以有如下6 种状态:New (新创建):未启动的线程;Runnable
- 公司编辑妹子需要爬取网页内容,叫我帮忙做了一简单的爬取工具这是爬取网页内容,像是这对大家来说都是不难得,但是在这里有一些小改动,代码献上,大
- pageHelper是一个非常方便实用的 Java 分页插件,可以轻松实现数据库分页查询。而在一对多的情况下,如果要实现主表和从表的联合分页
- QTableWidget 是 Qt 中的表格组件类。在窗体上放置一个 QTableWidget 组件后,可以在 Property Edito
- 本文实例讲述了java两种单例模式用法。分享给大家供大家参考,具体如下:按照加载方式的不同,单例模式有两种实现:private:只能在同一个
- ServletContext 基础知识获取 ServletContext对象有两种方式可以获取:使用 servletconfig 对象获取使
- 这篇文章主要介绍了spring web.xml指定配置文件过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价
- 之前在做分页时,很多朋友都是用Jquery分页插件,之前我就用的jquery.paper,有需要的朋友可以联系我,接下来小编给大家分享用Jq
- 本文实例讲述了Java基于享元模式实现五子棋游戏功能。分享给大家供大家参考,具体如下:一、模式定义享元模式,以共享的方式高效地支持大量的细粒
- 1.定义Token的注解,需要Token校验的接口,方法上加上此注解import java.lang.annotation.ElementT
- Netty是一个非常优秀的Socket框架。如果需要在SpringBoot开发的app中,提供Socket服务,那么Netty是不错的选择。
- 谷歌正式在I/O大会现场详细介绍了有关Android 7.0的大量信息。目前,我们已经知道,新一代Android操作系统将支持无缝升级,能够
- Android 动画实现几种方案在 Android 的 FrameWork 中,为我们提供三种动画的实现方式:逐帧(Frame)动画、视图/
- 当将类的某个数据成员声明为static时,该静态数据成员只能被定义一次,而且要被同类的所有对象共享。各个对象都拥有类中每一个普通数据成员的副
- 这篇文章主要介绍了Java判断用户名和密码过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可
- 1:RabbitMQ是个啥?(专业术语参考自网络)RabbitMQ是实现了高级消息队列协议(AMQP)的开源消息代理软件(亦称面向消息的中间
- 反射对效率有影响 慎用!!!1.对象结构public class BusinessDept {private String yea
- 1. Easy Rules 概述Easy Rules是一个Java规则引擎,灵感来自一篇名为《Should I use a Rules En
- 背景公司线上有个tomcat服务,里面合并部署了大概8个微服务,之所以没有像其他微服务那样单独部署,其目的是为了节约服务器资源,况且这8个服