【实战】聊天窗口的实现

  今天参考书上的例子,自己也实现了一个相对美观的聊天界面,过程如下:

一、第一步制作用于显示聊天内容的图片,使用SDK目录下的Tools下的draw9patch.bat来制作Nine-Patch图片,以便适用于各种分辨率的终端;

  需要注意的是在制作好之后保存的时候不能把保存的名称改掉,一定要带上保存时自动加上的.9,并且在引用的时候名称不用写.9即可,切记!在这浪费了一个多小时

二、编写主界面activity_main.xml,放一个ListView和LinearLayout,LinearLayout下面再放一个EditText(用于编写消息)和Button(用于发送消息)

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     android:id="@+id/LinearLayout1"
 4     android:layout_width="match_parent"
 5     android:layout_height="match_parent"
 6     android:orientation="vertical"
 7     android:background="#d8e0e8" >
 8 
 9     <ListView
10         android:id="@+id/msg_list_view"
11         android:layout_width="match_parent"
12         android:layout_height="0dp"
13         android:layout_weight="1"
14         android:divider="#0000" >
15     </ListView>
16     
17     
18     <LinearLayout 
19         android:layout_width="match_parent"
20         android:layout_height="wrap_content">
21         <EditText android:id="@+id/input_text"
22             android:layout_width="0dp"
23             android:layout_height="wrap_content"
24             android:layout_weight="1"
25             android:hint="Type something here"
26             android:maxLines="2"/>
27         
28         <Button 
29             android:id="@+id/send"
30             android:layout_width="wrap_content"
31             android:layout_height="wrap_content"
32             android:text="Send"/>
33         
34     </LinearLayout>
35 </LinearLayout>
activity_main.xml

三、新建消息实体类Msg

 1 package com.example.Entity;
 2 
 3 public class Msg {
 4     public static final int TYPE_RECEIVED = 0;
 5     public static final int TYPE_SEND = 1;
 6     private String content;//消息内容
 7     private int type;//消息类型,分为发送(TYPE_SEND)和接收的(TYPE_RECEIVED)
 8     
 9     public Msg(String content, int type) {
10         // TODO Auto-generated constructor stub
11         this.content = content;
12         this.type = type;
13     }
14 
15     public String getContent() {
16         return content;
17     }
18 
19     public int getType() {
20         return type;
21     }
22 
23 }
Msg

四、由于消息是用ListView显示的,那么接下来要编写ListView子项的布局,新建一个xml文件,msg_item.xml,发送和接收的消息在一个布局中,只要待会在代码中对布局的可见性进行控制即可;

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent"
 5     android:orientation="vertical" 
 6     android:padding="10dp">
 7     
 8     9-26行是在左侧出现的主要是在left_layout布局中放入了一个TextView来显示文字,left_layout布局中的背景就是我们做的Nine-Patch图片;;;代表的是接收的消息
 9     <LinearLayout
10         android:id="@+id/left_layout"
11            android:layout_width="wrap_content"
12            android:layout_height="wrap_content"
13            android:layout_gravity="start"
14            android:orientation = "vertical"
15         android:background="@drawable/message_left">
16         
17         <TextView 
18             android:id="@+id/left_msg"
19                android:layout_width="wrap_content"
20                android:layout_height="wrap_content"
21                android:layout_gravity="center"
22                android:layout_margin="10dp"
23                android:textColor="#fff"
24                android:textSize="15sp"/>
25 
26     </LinearLayout>
27     9-26行是在右侧出现的主要是在right_layout布局中放入了一个TextView来显示文字,right_layout布局中的背景就是我们做的Nine-Patch图片;;;代表的是发送的消息
28     <LinearLayout
29         android:id="@+id/right_layout"
30            android:layout_width="wrap_content"
31            android:layout_height="wrap_content"
32            android:layout_gravity="end"
33            android:orientation = "vertical"
34         android:background="@drawable/message_right">
35         
36         <TextView 
37             android:id="@+id/right_msg"
38                android:layout_width="wrap_content"
39                android:layout_height="wrap_content"
40                android:layout_gravity="center"
41                android:layout_margin="10dp"
42                android:textColor="#fff"
43                android:textSize="15sp"/>
44 
45     </LinearLayout>
46     
47 </LinearLayout>

 四、由于ListView要显示的数据需要通过适配器Adapter来实现,下面我们来建立一个适配器类MsgAdapter,继承于ArrayAdapter,并将泛型指定为Msg类;

 1 package com.example.uibestpractice;
 2 
 3 import java.util.List;
 4 
 5 import com.example.Entity.Msg;
 6 
 7 import android.content.Context;
 8 import android.view.LayoutInflater;
 9 import android.view.View;
10 import android.view.ViewGroup;
11 import android.widget.ArrayAdapter;
12 import android.widget.LinearLayout;
13 import android.widget.TextView;
14 
15 public class MsgAdapter extends ArrayAdapter<Msg> {
16     
17     //设置私有变量
18     private int resourceId;
19     
20     //建立三个参数的构造方法
21     public MsgAdapter(Context context, int textViewResourceId , List<Msg> objects) {
22 
23         //实现了ArrayAdapter类的构造方法
24         super(context, textViewResourceId,objects);
25         resourceId = textViewResourceId;
26     }
27     
28     //position就是你选择的 item的第几条从0开始
29     //convertView就是item上的布局layout或者组件
30     //ViewGroup parent 就是设置adapter的那个组件里面封装一个viewGroup用来盛放item
31     @Override
32     public View getView(int position, View convertView, ViewGroup parent) {
33         // TODO Auto-generated method stub
34         Msg msg = getItem(position);//获取当前项的Msg实例;
35         View view ;//定义一个View
36         ViewHolder viewHolder ;
37 //        定义一个ViewHolder,ViewHolder是一个内部类,    
38 //        就是一个持有者的类,他里面一般没有方法,只有属性,
39 //        作用就是一个临时的储存器,把你getView方法中每次返回的View存起来,可以下次再用。
40 //        这样做的好处就是不必每次都到布局文件中去拿到你的View,提高了效率
41         
42         //判断convertView对象是否为空,如果为空就重新加载;
43         if(convertView == null)
44         {
45             //使用Layoutinflater为这个子项加载我们传入的布局(resourceId),
46             view = LayoutInflater.from(getContext()).inflate(resourceId, null);
47             //实例化内部类viewHolder
48             viewHolder = new ViewHolder();
49             //将控件的实例都存在ViewHolder中
50             viewHolder.leftLayout =(LinearLayout) view.findViewById(R.id.left_layout);
51             viewHolder.rightLayout =(LinearLayout) view.findViewById(R.id.right_layout);
52             viewHolder.leftMag = (TextView) view.findViewById(R.id.left_msg);
53             viewHolder.rightMag = (TextView) view.findViewById(R.id.right_msg);
54             //把viewHolder通过View的setTag方法存放起来;
55             view.setTag(viewHolder);
56         }
57         else//如果不为空,则重新调用convertView;不必重新加载
58         {
59             view = convertView;
60             viewHolder = (ViewHolder) view.getTag();//取出viewHolder,也就取出了已经加载过得数据
61         }
62         
63         if(msg.getType() == msg.TYPE_RECEIVED)//如果是接收的消息则左侧显示布局和文字,右侧隐藏
64         {
65             viewHolder.leftLayout.setVisibility(View.VISIBLE);
66             viewHolder.rightLayout.setVisibility(View.GONE);
67             viewHolder.leftMag.setText(msg.getContent());
68         }
69         else if(msg.getType() == msg.TYPE_SEND)//如果是发送的消息则右侧显示布局和文字,左侧隐藏
70         {
71             viewHolder.rightLayout.setVisibility(View.VISIBLE);
72             viewHolder.rightMag.setText(msg.getContent());
73             viewHolder.leftLayout.setVisibility(View.GONE);
74         }
75         //返回一个View
76         return view;
77     }
78     class ViewHolder//临时存储器,把getView方法中每次返回的View存起来,可以下次再用
79     {
80         LinearLayout leftLayout ;
81         LinearLayout rightLayout ;
82         TextView leftMag;
83         TextView rightMag;
84         
85     }
86 }
MsgAdapter

 五、最后来实现MainActivity.java的代码,为ListView初始化数据,并设置一些响应事件,完成最后的操作

 1 package com.example.uibestpractice;
 2 
 3 import java.util.ArrayList;
 4 import java.util.List;
 5 
 6 import com.example.Entity.Msg;
 7 
 8 import android.app.Activity;
 9 import android.os.Bundle;
10 import android.view.Menu;
11 import android.view.MenuItem;
12 import android.view.View;
13 import android.view.View.OnClickListener;
14 import android.widget.Button;
15 import android.widget.EditText;
16 import android.widget.ListView;
17 
18 public class MainActivity extends Activity {
19 
20     private ListView msgListView;//定义ListView
21     private EditText inputText;//定义EditText
22     private Button send;//定义Button
23     private MsgAdapter adapter;//定义MsgAdapter
24     private List<Msg> msgList = new ArrayList<Msg>();//实例化一个泛型为Msg的List
25     
26     @Override
27     protected void onCreate(Bundle savedInstanceState) {
28         super.onCreate(savedInstanceState);
29         setContentView(R.layout.activity_main);
30         
31         //初始化数据
32         initMsgs();
33         
34         //调用MsgAdapter的构造方法实例化adapter,
35         adapter = new MsgAdapter(MainActivity.this, R.layout.msg_item, msgList);
36         
37         //分别实例化EditText、Button、ListView
38         inputText = (EditText) findViewById(R.id.input_text);
39         send = (Button) findViewById(R.id.send);
40         msgListView = (ListView) findViewById(R.id.msg_list_view);
41         
42         //为ListView加适配器;
43         msgListView.setAdapter(adapter);
44         
45         //设置send的点击事件,响应用户操作
46         send.setOnClickListener(new OnClickListener() {
47             
48             @Override
49             public void onClick(View v) {
50                 
51                 //定义内容获取用户在EditText中输入的字符串
52                 String content = inputText.getText().toString();
53                 
54                 //如果字符串不为空,把数据添加到 msgList中
55                 if(!"".equals(content))
56                 {
57                     Msg msg = new Msg(content , Msg.TYPE_SEND);
58                     msgList.add(msg);
59                     
60                     //动态更新ListView
61                     adapter.notifyDataSetChanged();
62                     
63                     //将列表移动到刚发的消息处,即msgList的最大位置
64                     msgListView.setSelection(msgList.size());
65                     
66                     //把输入框置空
67                     inputText.setText("");
68                 }
69             }
70         });
71     }
72 
73     private void initMsgs() {
74         // TODO Auto-generated method stub
75         Msg msg1 = new Msg("Hello guy!",Msg.TYPE_RECEIVED);//往msgList中添加接收数据
76         msgList.add(msg1);
77         Msg msg2 = new Msg("Hello,Who is that?",Msg.TYPE_SEND);//往msgList中添加发送数据
78         msgList.add(msg2);
79         Msg msg3 = new Msg("This is Tom,Nice talking to you.",Msg.TYPE_RECEIVED);//往msgList中添加接收数据
80         msgList.add(msg3);
81     }
82 
83 
84 }
MainActivity.java

至此,此次实战结束,运行效果图:

原文地址:https://www.cnblogs.com/csschn/p/5248976.html