这段时间做的东西比较杂,但是对学习来说还是很有帮助的,这次做的基于socket的即时通讯也是为了更加了解IM,本来是打算使用openfire或者apollo服务器来实现的,但是中途时间上的问题,临时改了需求,后期的语音通话还是要借助第三方服务器的,这里主要是自己用myeclipse写了一个简单的代理服务器,主要是将客户端发来的消息转发到已经保存到链表中的socket中,实现比较简单,主要是解决发送图片的模块,我参考了很多文章,但是大多写的都不是很全,故自己写了一下,[socket即时通讯源码](https://github.com/firesmog/MyGreenDao),写这篇博客,一是为了记录自己的学习进度,而是希望能给正在学习路上的各位同学一点点帮助。
这里的服务端是采用myeclipse写的,比较简单单,主要负责将任意客户端传过来的消息的进行转发,然后使得客户端收到信息后能在自己的界面上进行展示,具体代码如下,仅供参考。
public class tcpservice {
private static final int SERVERPORT = 8090;
private static List mClientList = new ArrayList();
private ExecutorService mExecutorService;
private ServerSocket mServerSocket;
public static void main(String[] args) {
new tcpservice();
}
public tcpservice() {
try {
//服务端套接字,这里给定客户端要连接的目标端口即可
mServerSocket = new ServerSocket(SERVERPORT);
//使用线程池,来一个客户端,开一个线程处理
mExecutorService = Executors.newCachedThreadPool();
System.out.println("start...");
Socket client = null;
while (true) {
//监听客户端的连接,一旦客户端连接上,则将客户端套接字赋值给client
client = mServerSocket.accept();
//在链表中保存客户端,以便后面的消息转发
mClientList.add(client);
System.out.println(client.toString());
//开启线程
mExecutorService.execute(new ThreadServer(client));
}
}
catch (IOException e) {
e.printStackTrace();
}
}
//新建自己的线程类,实现线程内run方法的实现
static class ThreadServer implements Runnable {
private Socket mSocket;
private BufferedReader mBufferedReader;
private PrintWriter mPrintWriter;
private String mStrMSG;
//构造方法,将客户端套接字socket传进来
public ThreadServer(Socket socket) throws IOException {
this.mSocket = socket;
//获得客户端输入流,用于读取客户端数据
mBufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
mStrMSG = "user:"+this.mSocket.getInetAddress()+" come total:" + mClientList.size();
}
//run方法的实现
public void run() {
try {
//判断客户端发送过来的信息是否是要退出聊天
while ((mStrMSG = mBufferedReader.readLine()) != null) {
if (mStrMSG.trim().equals("exit")) {
mClientList.remove(mSocket);
mBufferedReader.close();
mPrintWriter.close();
mStrMSG = "user:"+this.mSocket.getInetAddress()+" exit total:" + mClientList.size();
mSocket.close();
sendMessage();
break;
}
else {
// mStrMSG = mSocket.getInetAddress() + ":" + mStrMSG;
System.out.println( mStrMSG);
sendMessage();
}
}
}
catch (IOException e) {
e.printStackTrace();
}
}
private void sendMessage() throws IOException {
System.out.println(mStrMSG);
//遍历所有的客户端套接字,将消息转发出去
for (Socket client : mClientList) {
mPrintWriter = new PrintWriter(client.getOutputStream(), true);
mPrintWriter.println(mStrMSG);
mPrintWriter.flush();
}
}
}
}
服务端就介绍到,这里,因为实现比较简单,所以也不多做赘述。
这里的客户端实在Androidstudio上实现的,逻辑不难,主要是界面上的操作,大家可以参考一下。这里先贴出界面图,比较丑陋,大家见谅。
主界面主要采用的ViewPger+Recycleview,发送表情主要是采用Recycleview+girdView+EditText,,下面写给出主界面布局,以及聊天界面布局,大家仅参考,具体内容,数据资源都在源码中,大家自行下载。
//主界面
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main"
android:layout_width="match_parent" android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="example.com.myapplication.MainActivity">
<example.com.myapplication.MyViewPager.MyViewPager
android:id="@+id/vp_main"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" >
android:persistentDrawingCache="animation"
example.com.myapplication.MyViewPager.MyViewPager>
<RadioGroup
android:id="@+id/rd_group"
android:layout_width="match_parent"
android:layout_height="90dp"
android:layout_alignParentBottom="true"
android:orientation="horizontal">
<RadioButton
android:id="@+id/rd_1"
style="@style/tab_menu_item"
android:drawableTop="@drawable/message"
android:text="消息"/>
<RadioButton
android:id="@+id/rd_2"
style="@style/tab_menu_item"
android:drawableTop="@drawable/contactor"
android:text="联系人"/>
<RadioButton
android:id="@+id/rd_3"
style="@style/tab_menu_item"
android:drawableTop="@drawable/statues"
android:text="动态"/>
RadioGroup>
LinearLayout>
//聊天界面
"http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:orientation="vertical"
>
.support.v7.widget.RecyclerView
android:id="@+id/msg_recyclerView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
.support.v7.widget.RecyclerView>
"match_parent"
android:layout_height="60dp"
android:orientation="horizontal"
>
"@+id/iv_motion"
android:onClick="true"
android:layout_marginLeft="10dp"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="@drawable/chat_icon"/>
"true"
android:id="@+id/input_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:hint="Type something here"
android:maxLines="2"/>
.support.v4.view.ViewPager
android:paddingTop="5dp"
android:id="@+id/vp_motion"
android:layout_width="match_parent"
android:layout_height="150dp"
android:visibility="gone">
.support.v4.view.ViewPager>
聊天界面当中的girdview是为了展示图片内容的,在初始的时候采用Gone将其隐藏起来,点击的时候将其设置为Visable展示出来,这里要注意的是图片的显示与软键盘弹出来的冲突,具体完全解决问题的做法,本人还没做好,在本demo中只是做了点强制的切换,隐藏,使得在软键盘和图片展示界面切换的时候有点卡顿,大家感兴趣的自己解决一下,解决好了的可以教一下我,谢谢。这里顺便说一下,主界面中使用了MyViewPger是自定义的viewpager主要目的,其实是我自己之前做仿qq的Recycleview的侧滑删除Item操作时,测试事件分发机制用的,感兴趣的同学可以自行添加事件分发方法,打log查看一下事件分发顺序。这里已经有点偏离话题,大家勿怪。
MyViewPger代码如下:
package example.com.myapplication.MyViewPager;
import android.content.Context;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
/**
* Created by firesmog on 2017/2/22.
*/
public class MyViewPager extends ViewPager {
private boolean noScroll = false;
public MyViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}
public MyViewPager(Context context) {
super(context);
}
public void setNoScroll(boolean noScroll) {
this.noScroll = noScroll;
}
@Override
public void scrollTo(int x, int y) {
super.scrollTo(x, y);
}
//下面内容其实是为了测试事假分发,其实有点绕,一段时间不做,就会有点生疏
@Override
public boolean onTouchEvent(MotionEvent arg0) {
/* return false;//super.onTouchEvent(arg0); */
Log.i(MyViewPager.class.getSimpleName(), ” onTouchEvent” + ” event = ” + arg0);
if (noScroll){
return false;
}
else
return true;
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev){
Log.i(MyViewPager.class.getSimpleName(), ” dispatchTouchEvent” + ” event = ” + ev + ” noScroll = ” + noScroll);
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent arg0) {
Log.i(MyViewPager.class.getSimpleName(), ” onInterceptTouchEvent” + ” event = ” + arg0);
if (noScroll) {
return false;
}
else
return super.onInterceptTouchEvent(arg0);
}
@Override
public void setCurrentItem(int item, boolean smoothScroll) {
super.setCurrentItem(item, smoothScroll);
}
@Override
public void setCurrentItem(int item) {
super.setCurrentItem(item);
}
}
到了这里的话,就需要给girdview,Recycleview等添加适配器了,这两个适配器在写的时候注意的地方有很多,我也是参考了别人的代码,做了修改,时间有点久,不记得是谁的博客了,见谅。首先需要展示图片,所以列出girdview的adapter。代码如下所示。
package example.com.myapplication.Adapter;
import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.List;
import example.com.myapplication.Bean.HeaderViewBean;
import example.com.myapplication.R;
/**
* Created by firesmog on 2017/3/3.
*/
public class GridViewAdapter extends BaseAdapter {
private List mDatas;
private LayoutInflater mLayoutInflater;
private Context context;
private int columnWidth;
/**
* 页数下标,从0开始
*/
private int mIndex;
/**
* 每页显示最大条目个数 ,默认是dimes.xml里 HomePageHeaderColumn 属性值的两倍
*/
private int mPageSize;
/**
* @param context 上下文
* @param mDatas 传递的数据
* @param columnWidth
* @param mIndex 页码
*/
public GridViewAdapter(Context context, List mDatas, int columnWidth, int mIndex) {
this.context = context;
this.mDatas = mDatas;
mLayoutInflater = LayoutInflater.from(context);
this.mIndex = mIndex;
mPageSize =28;
this.columnWidth= columnWidth;
}
public GridViewAdapter(Context context, List mDatas, int index) {
this.context = context;
this.mDatas = mDatas;
mLayoutInflater = LayoutInflater.from(context);
this.mIndex = index;
mPageSize =28;
}
/**
* 先判断数据集的大小是否足够显示满本页?mDatas.size() > (mIndex+1)*mPageSize,
* 如果够,则直接返回每一页显示的最大条目个数mPageSize,
* 如果不够,则有几项返回几,(mDatas.size() - mIndex * mPageSize);
*/
@Override
public int getCount() {
return mDatas.size() > (mIndex + 1) * mPageSize ? mPageSize : (mDatas.size() - mIndex * mPageSize);
}
@Override
public Object getItem(int position) {
return mDatas.get(position + mIndex * mPageSize);
}
@Override
public long getItemId(int position) {
return position + mIndex * mPageSize;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
Log.i("TAG", "position:" + position);
ViewHolder vh = null;
if (convertView == null) {
convertView = mLayoutInflater.inflate(R.layout.item_gird, parent, false);
vh = new ViewHolder();
vh.iv = (ImageView) convertView.findViewById(R.id.id_iv_icon);
convertView.setTag(vh);
} else {
vh = (ViewHolder) convertView.getTag();
}
/**
* 在给View绑定显示的数据时,计算正确的position = position + mIndex * mPageSize,
*/
int pos = position + mIndex * mPageSize;
vh.iv.setImageResource(mDatas.get(pos).iconRes);
return convertView;
}
class ViewHolder {
public TextView tv;
public ImageView iv;
}
}
有了展示图片的adapter的界面后,主要就是聊天对话框的dapter,代码如下:
package example.com.myapplication.Adapter;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import java.util.List;
import example.com.myapplication.Bean.Msg;
import example.com.myapplication.R;
/**
* Created by firesmog on 2017/3/3.
*/
public class MsgAdapter extends RecyclerView.Adapter.ViewHolder>
{
List msgList;
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
{
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_recycly, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(ViewHolder holder, int position)
{
Msg msg = msgList.get(position);
if (msg.getType() == Msg.TYPE_RECEIVE)
{
holder.leftLayout.setVisibility(View.VISIBLE);
holder.rightLayout.setVisibility(View.GONE);
holder.leftMsg.setText(msg.getContent());
} else if (msg.getType() == Msg.TYPE_SEND)
{
holder.rightLayout.setVisibility(View.VISIBLE);
holder.leftLayout.setVisibility(View.GONE);
holder.rightMsg.setText(msg.getContent());
}
}
public MsgAdapter(List msgs)
{
this.msgList = msgs;
}
@Override
public int getItemCount()
{
return msgList.size();
}
static class ViewHolder extends RecyclerView.ViewHolder
{
LinearLayout leftLayout;
LinearLayout rightLayout;
TextView leftMsg;
TextView rightMsg;
ViewHolder(View view)
{
super(view);
//这里要分为左边对话框
leftLayout = (LinearLayout) view.findViewById(R.id.left_layout);
//这里要分为右边对话框
rightLayout = (LinearLayout) view.findViewById(R.id.right_layout);
//这里要分为左边消息
leftMsg = (TextView) view.findViewById(R.id.left_msg);
//这里要分为右边消息
rightMsg = (TextView) view.findViewById(R.id.right_msg);
}
}
}
最后这里附上聊天Activity的代码,中间主要实现了socket连接、发送,在输入图片是,对图片的转换,这
里的将图片显示在编辑框中方法也写在了该activity中,接收服务器的图片再经过转化后才能在对话框中将图
片显示出来,这里注意,获取到的图片内容,并不是图片本身,而是用一个与图片资源对应的字符串数组来
替代图片,但是编辑框和对话框并不能通过string将图片展示出来,需要将之先转化为spannerString,但是
我们最好收到服务器的图片显示的时候,使用handler传输时,进行传值时,必须用CharSequence而不是
String ,说的乱七八糟,具体大家看代码吧。**关键点就是编辑框、对话框不能直接显示图片,它们只能显示
String,所以要将图片先转化对应的SpannerString传到对话框中才能显示,这是个人笨拙的简易理解,应
该有错误**
public class ChatActivity extends AppCompatActivity implements View.OnClickListener {
private ViewPager mViewPager;
private List mViewPagerGridList;
private static final String SERVERIP = "172.28.12.130";
private static final int SERVERPORT = 8090;
private Thread mThread = null;
private Socket mSocket = null;
private BufferedReader mBufferedReader = null;
private PrintWriter mPrintWriter = null;
private static String mStrMSG = "";
private static String TAG = "TCP";
private List msgList = new ArrayList<>();
private EditText inputText;
private ImageView iv_motion;
private Boolean IsShow=false;
private ViewPager vp_motion;
private List mDatas = new ArrayList<>();
private Button btnSend;
private Button btLogin;
private RecyclerView recyclerView;
private MsgAdapter adapter;
private int[] drawable;
private TextView tv_Show;
private boolean IsSend=false;
private String[] faceScr;
private Pattern pattern;
private HashMap faceBook;
private Handler handler = new Handler() {
// 该方法运行在主线程中
// 接收到handler发送的消息,对UI进行操作
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
if (msg.what == 1) {
// tv_Show.setText(msg.getData().getCharSequence("time"));
//这里必须是CharSequence,如果传过来是String,图片是显示不出来的,大家可试一下
msgList.add(new Msg(msg.getData().getCharSequence("time"), Msg.TYPE_SEND));
adapter.notifyItemInserted(msgList.size() - 1);
recyclerView.scrollToPosition(msgList.size() - 1);
}else if(msg.what==2){
//这里必须是CharSequence,如果传过来是String,图片是显示不出来的,大家可试一下
msgList.add(new Msg(msg.getData().getCharSequence("recive"), Msg.TYPE_RECEIVE));
adapter.notifyItemInserted(msgList.size() - 1);
recyclerView.scrollToPosition(msgList.size() - 1);
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chat);
initMsg();
initDatas();
//连接服务器
ConnectServ();
btnSend = (Button) this.findViewById(R.id.btnsend);
// btLogin=(Button) this.findViewById(R.id.btLogin);
inputText = (EditText) this.findViewById(R.id.input_text);
mViewPager = (ViewPager) findViewById(R.id.vp_motion);
iv_motion = (ImageView) findViewById(R.id.iv_motion);
vp_motion=(ViewPager)findViewById(R.id.vp_motion);
recyclerView = (RecyclerView) this.findViewById(R.id.msg_recyclerView);
mViewPagerGridList = new ArrayList<>();
LayoutInflater inflater = getLayoutInflater();
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(linearLayoutManager);
adapter = new MsgAdapter(msgList);
recyclerView.setAdapter(adapter);
btnSend.setOnClickListener(this);
//btLogin.setOnClickListener(this);
iv_motion.setOnClickListener(this);
inputText.setOnClickListener(this);
//下面部分是针对girdview的,对girdview进行相关操作,显示图片
**// 每页显示最大条目个数
int pageSize = 28;
//页数
int pageCount = (int) Math.ceil(mDatas.size() * 1.0 / pageSize);
//获取屏幕的宽度,单位px
int screenWidth = getResources().getDisplayMetrics().widthPixels;
//获取GridView中每个item的宽度 = 屏幕宽度 / GridView显示的列数
int columnWidth = (int) Math.ceil((screenWidth) * 1.0 / 7);
for (int index = 0; index < pageCount; index++) {
GridView grid = (GridView) inflater.inflate(R.layout.gird_motion, mViewPager, false);
//设置GridView每个item的宽度
grid.setColumnWidth(columnWidth);
//设置GirdView的布局参数(宽和高,宽为包裹父容器,高 = columnWidth)
grid.setLayoutParams(new AbsListView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, columnWidth));
grid.setAdapter(new GridViewAdapter(this, mDatas, index));
//响应图片选择事件
grid.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView> parent, View view, int position, long id) {
Log.i("TAG",position+"******************"+id+"");
faceReplace(getApplicationContext(),drawable[(int) id],faceScr[(int)id],inputText);
}
});
mViewPagerGridList.add(grid);**
}
mViewPager.setAdapter(new MyViewPagerAdapter(mViewPagerGridList));
}
//发送信息到服务器
public void sendMsg(){
//因为,聊天界面分为发送端和接收端,两端的数据分别显示在左边和右边,需要用IsSend标记自己是发送端
IsSend=true;
if (!content.equals(""))
{
mPrintWriter.println(content);
mPrintWriter.flush();
inputText.setText("");
}
mThread = new Thread(mRunnable);
mThread.start();
}
private Runnable mRunnable = new Runnable() {
public void run() {
while (true) {
try {
if ((mStrMSG = mBufferedReader.readLine()) != null) {
if(IsSend){
Message message=new Message();
Bundle bundle=new Bundle();
//这里是将接收到的消息,先判断是否有图片,如果有在抽取出来显示,
//而且这里返回值我用的是CharSequence,如果是String则显示不出图片
CharSequence addSmileySpans=addSmileySpans(mStrMSG);
bundle.putCharSequence("time",addSmileySpans);
message.setData(bundle);//bundle传值,耗时,效率低
handler.sendMessage(message);//发送message信息
message.what=1;//标志是哪个线程传数据
}else{
Message message=new Message();
Bundle bundle=new Bundle();
CharSequence addSmileySpans=addSmileySpans(mStrMSG);
bundle.putCharSequence("recive",addSmileySpans);
message.setData(bundle);//bundle传值,耗时,效率低
handler.sendMessage(message);//发送message信息
message.what=2;//标志是哪个线程传数据
}
IsSend=false;
}
} catch (Exception e) {
Log.e(TAG, e.toString());
}
}
}
};
private void initMsg()
{
Msg msg1 = new Msg("hello sealong", Msg.TYPE_RECEIVE);
msgList.add(msg1);
Msg msg2 = new Msg("hello peipei", Msg.TYPE_SEND);
msgList.add(msg2);
Msg msg = new Msg("What are you doing", Msg.TYPE_RECEIVE);
msgList.add(msg);
}
public void ConnectServ(){
new Thread(new Runnable() {
@Override
public void run() {
try {
Log.i(TAG, "lianjie ");
// ①Socket实例化,连接服务器
mSocket = new Socket(SERVERIP, SERVERPORT);
// ②获取Socket输入输出流进行读写操作
mBufferedReader = new BufferedReader(new InputStreamReader(mSocket.getInputStream()));
mPrintWriter = new PrintWriter(mSocket.getOutputStream(), true);
} catch (Exception e) {
// TODO: handle exception
Log.e(TAG, e.toString());
}
}
}).start();
}
private void initDatas() {
initMotion();
for(int i=0;inew HeaderViewBean("Item " + (i + 1), drawable[i]);
mDatas.add(headerViewBean);
headerViewBean=null;
}
}
//下面两个数据时加载图片资源,并且为图片资源设置对应的名称,用于后期使用正则表达式将图片分离出来
**public void initMotion(){
drawable = new int[]
{ R.drawable.f000,R.drawable.f001,R.drawable.f002,R.drawable.f003,R.drawable.f004,R.drawable.f005,
R.drawable.f006,R.drawable.f007,R.drawable.f008,R.drawable.f009,R.drawable.f010,R.drawable.f011,
R.drawable.f012,R.drawable.f013,R.drawable.f014,R.drawable.f015,R.drawable.f016,R.drawable.f017,
R.drawable.f018,R.drawable.f019,R.drawable.f020,R.drawable.f021,R.drawable.f022,R.drawable.f023,
R.drawable.f024,R.drawable.f025,R.drawable.f026,R.drawable.f027,R.drawable.f059,R.drawable.f028,
R.drawable.f029,R.drawable.f030,R.drawable.f031,R.drawable.f032,R.drawable.f033,R.drawable.f034,
R.drawable.f035,R.drawable.f036,R.drawable.f037,R.drawable.f038,R.drawable.f039,R.drawable.f040,
R.drawable.f041,R.drawable.f042,R.drawable.f043,R.drawable.f044,R.drawable.f045,R.drawable.f046,
R.drawable.f047,R.drawable.f048,R.drawable.f049,R.drawable.f050,R.drawable.f051,R.drawable.f052,
R.drawable.f053,R.drawable.f054,R.drawable.f055,R.drawable.f056,R.drawable.f057,R.drawable.f058,
};
faceScr = new String[] { "#000", "#001", "#002", "#003", "#004",
"#005", "#006", "#007", "#008", "#009", "#010", "#011", "#012",
"#013", "#014", "#015", "#016", "#017", "#018", "#019", "#020",
"#021", "#022", "#023", "#024", "#025", "#026", "#027", "#028",
"#029", "#030", "#031", "#032", "#033", "#034", "#035", "#036",
"#037", "#038", "#039", "#040", "#041", "#042", "#043", "#044",
"#045", "#046", "#047", "#048", "#049", "#050", "#051", "#052",
"#053", "#054", "#055", "#056", "#057", "#058", "#059" };
faceBook=buildSmileyToRes();
pattern=buildPattern();
}**
**//下面的方法是抽取出图片,并将图片转化SpannableString
private HashMap buildSmileyToRes() {
/**
* 文字和ID不匹配,异常
*/
if (drawable.length != faceScr.length) {
throw new IllegalStateException("Smiley resource ID/text mismatch");
}
HashMap smileyToRes = new HashMap(
faceScr.length);
for (int i = 0; i < faceScr.length; i++) {
smileyToRes.put(faceScr[i], drawable[i]);
}
return smileyToRes;
}
public void showMotion(){
if(IsShow==false){
InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(inputText.getWindowToken(),0);
vp_motion .setVisibility(View.VISIBLE);
IsShow=true;
}else {
vp_motion.setVisibility(View.GONE);
IsShow=false;
}
}
public void faceReplace(Context context, int resourceId,
String spannableStr, EditText edit) {
/**
* 根据ID获取图片资源
*/
Drawable dr = context.getResources().getDrawable(resourceId);
dr.setBounds(0, 0, dr.getIntrinsicWidth()*4/5, dr.getIntrinsicHeight()*4/5);
/**
* SpannableString 配置被替代的文字描述;ImageSpan 配置替代的图片
*/
SpannableString spanStr = new SpannableString(spannableStr);
ImageSpan spanImg = new ImageSpan(dr, ImageSpan.ALIGN_BASELINE);
/**
* 将文字如【smile】替换为表情 参数二、参数三分别指定所要替代字符的位置
*/
spanStr.setSpan(spanImg, 0, spanStr.length(), spanStr.SPAN_EXCLUSIVE_EXCLUSIVE);
edit.append(spanStr);
}
public CharSequence addSmileySpans(CharSequence text) {
SpannableStringBuilder builder = new SpannableStringBuilder(text);
Matcher matcher = pattern.matcher(text);
while (matcher.find()) {
int resId = faceBook.get(matcher.group());
Drawable dr = this.getResources().getDrawable(resId);
dr.setBounds(0, 0, dr.getIntrinsicWidth()*4/5, dr.getIntrinsicHeight()*4/5);
builder.setSpan(new ImageSpan(dr, ImageSpan.ALIGN_BASELINE),
matcher.start(), matcher.end(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
return builder;
}
private Pattern buildPattern() {
StringBuilder patternString = new StringBuilder(faceScr.length * 3);
patternString.append('(');
for (String s : faceScr) {
patternString.append(Pattern.quote(s));
patternString.append('|');
}
patternString.replace(patternString.length() - 1,
patternString.length(), ")");
return Pattern.compile(patternString.toString());
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btnsend:
sendMsg();
break;
case R.id.iv_motion:
showMotion();
break;
case R.id.input_text:
vp_motion.setVisibility(View.GONE);
break;
}**
}
}
最后给大家道歉一下,因为,本人写的博客不多,有点乱,时间也有点紧,所以可能看起来会很费力,希望大家谅解,也真心希望能帮到大家,该demo确实是亲测可用的。