Android学习笔记(十二)——实战:制作一个聊天界面

  //此系列博文是《第一行Android代码》的学习笔记,如有错漏,欢迎指正!

  运用简单的布局知识,我们可以来尝试制作一个聊天界面。

一、制作 Nine-Patch 图片 :

  Nine-Patch图片是一种被特殊处理过的 png 图片,能够指定哪些区域可以被拉伸而哪些区域不可以。一般用来作为聊天信息的背景。在此我们先准备一张png图片。然后在 Android sdk 目录下有一个 tools 文件夹,在这个文件夹中找到 draw9patch.bat文件。 双击打开之后, 在导航栏点击 File→Open 9-patch将 msg.png加载进来。我们可以在图片的四个边框绘制一个个的小黑点, 在上边框和左边框绘制的部分就表示当图片需要拉伸时就拉伸黑点标记的区域, 在下边框和右边框绘制的部分则表示内容会被放置的区域。右侧是三种不同拉伸情况下的预览图:

  

  最后点击导航栏 File→Save 9-patch 把绘制好的图片进行保存,此时的文件名就是msg_left.9.png。同样,我们制作一张msg_right.9.png。

二、编写布局文件:  

 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:background="#d8e0e8"
 6     android:orientation="vertical" >
 7     <ListView
 8         android:id="@+id/msg_list_view"
 9         android:layout_width="match_parent"
10         android:layout_height="0dp"
11         android:layout_weight="1"
12         android:divider="#0000" >
13     </ListView>
14     <LinearLayout
15         android:layout_width="match_parent"
16         android:layout_height="wrap_content" >
17         <EditText
18             android:id="@+id/input_text"
19             android:layout_width="0dp"
20             android:layout_height="wrap_content"
21             android:layout_weight="1"
22             android:hint="Type somthing here"
23             android:maxLines="2" />
24         <Button
25             android:id="@+id/send"
26             android:layout_width="wrap_content"
27             android:layout_height="wrap_content"
28             android:text="Send" />
29     </LinearLayout>
30 </LinearLayout>

  我们指定了一个ListView用来显示聊天内容,另外还有一个EditText和button。其中ListView 中用到了一个 android:divider属性,它可以指定 ListView 分隔线的颜色,这里#0000 表示将分隔线设为透明色。

三、编写Msg类:

  为了后续的操作,我们定义一个Msg类:

 1 public class Msg {
 2     public static final int TYPE_RECEIVED = 0;
 3     public static final int TYPE_SENT = 1;
 4     private String content;
 5     private int type;
 6     public Msg(String content, int type) {
 7         this.content = content;
 8         this.type = type;
 9     }
10     public String getContent() {
11         return content;
12     }
13     public int getType() {
14         return type;
15     }
16 }

  Msg 类中只有两个字段,content表示消息的内容,type 表示消息的类型。其中消息类型有两个值可选,TYPE_RECEIVED 表示这是一条收到的消息,TYPE_SENT 表示这是一条发出的消息。

四、编写ListView的子布局:

  新建 msg_item.xml:

 1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2     android:layout_width="match_parent"
 3     android:layout_height="match_parent"
 4     android:orientation="vertical"
 5     android:padding="10dp" >
 6     <LinearLayout
 7         android:id="@+id/left_layout"
 8         android:layout_width="wrap_content"
 9         android:layout_height="wrap_content"
10         android:layout_gravity="left"
11         android:background="@drawable/msg_left" >
12         <TextView
13             android:id="@+id/left_msg"
14             android:layout_width="wrap_content"
15             android:layout_height="wrap_content"
16             android:layout_gravity="center"
17             android:layout_margin="10dp"
18             android:textColor="#fff" />
19     </LinearLayout>
20     <LinearLayout
21         android:id="@+id/right_layout"
22         android:layout_width="wrap_content"
23         android:layout_height="wrap_content"
24         android:layout_gravity="right"
25         android:background="@drawable/msg_right" >
26         <TextView
27             android:id="@+id/right_msg"
28             android:layout_width="wrap_content"
29             android:layout_height="wrap_content"
30             android:layout_gravity="center"
31             android:layout_margin="10dp" />
32     </LinearLayout>
33 </LinearLayout>

  这里我们让收到的消息居左对齐,发出的消息居右对齐,并且分别使用 message_left.9.png和 message_right.9.png 作为背景图。这里我们让收到的消息和发出的消息都放在同一个布局里,在稍后在代码中我们根据消息的类型来决定隐藏和显示哪种消息。

五、创建 ListView的适配器类:

  同样,我们需要新建一个适配器类:

 1 public class MsgAdapter extends ArrayAdapter<Msg> {
 2     private int resourceId;
 3     public MsgAdapter(Context context, int textViewResourceId, List<Msg>
 4             objects) {
 5         super(context, textViewResourceId, objects);
 6         resourceId = textViewResourceId;
 7     }
 8     @Override
 9     public View getView(int position, View convertView, ViewGroup parent) {
10         Msg msg = getItem(position);
11         View view;
12         ViewHolder viewHolder;
13         if (convertView == null) {
14             view = LayoutInflater.from(getContext()).inflate(resourceId, null);
15             viewHolder = new ViewHolder();
16             viewHolder.leftLayout = (LinearLayout) view.findViewById(R.id.left_layout);
17             viewHolder.rightLayout = (LinearLayout) view.findViewById(R.id.right_layout);
18             viewHolder.leftMsg = (TextView) view.findViewById(R.id.left_msg);
19             viewHolder.rightMsg = (TextView) view.findViewById(R.id.right_msg);
20             view.setTag(viewHolder);
21         }
22         else {
23             view = convertView;
24             viewHolder = (ViewHolder) view.getTag();
25         } //提高ListView的效率
26
27         if (msg.getType() == Msg.TYPE_RECEIVED) {
28 // 如果是收到的消息,则显示左边的消息布局,将右边的消息布局隐藏
29             viewHolder.leftLayout.setVisibility(View.VISIBLE);
30             viewHolder.rightLayout.setVisibility(View.GONE);
31             viewHolder.leftMsg.setText(msg.getContent());
32         } else if(msg.getType() == Msg.TYPE_SENT) {
33 // 如果是发出的消息,则显示右边的消息布局,将左边的消息布局隐藏
34             viewHolder.rightLayout.setVisibility(View.VISIBLE);
35             viewHolder.leftLayout.setVisibility(View.GONE);
36             viewHolder.rightMsg.setText(msg.getContent());
37         }
38         return view;
39     }
40     class ViewHolder {
41         LinearLayout leftLayout;
42         LinearLayout rightLayout;
43         TextView leftMsg;
44         TextView rightMsg;
45     }
46 }

  代码中在 getView()方法中增加了对消息类型的判断。如果这条消息是收到的,则显示左边的消息布局,如果这条消息是发出的,则显示右边的消息布局。

六、添加主活动的逻辑:

 1 public class MainActivity extends AppCompatActivity {
 2     private ListView msgListView;
 3     private EditText inputText;
 4     private Button send;
 5     private MsgAdapter adapter;
 6     private List<Msg> msgList = new ArrayList<Msg>();
 7     private int index = 1;
 8     @Override
 9     protected void onCreate(Bundle savedInstanceState) {
10         super.onCreate(savedInstanceState);
11         //requestWindowFeature(Window.FEATURE_NO_TITLE);
12         setContentView(R.layout.activity_main);
13         initMsgs(); // 初始化消息数据
14         adapter = new MsgAdapter(MainActivity.this, R.layout.msg_item, msgList);
15         inputText = (EditText) findViewById(R.id.input_text);
16         send = (Button) findViewById(R.id.send);
17         msgListView = (ListView) findViewById(R.id.msg_list_view);
18         msgListView.setAdapter(adapter);
19         send.setOnClickListener(new View.OnClickListener() {
20             @Override
21             public void onClick(View v) {
22                 String content = inputText.getText().toString();
23                 if (!"".equals(content)) {//content内容不为空时
24                     index++;
25                     Msg msg = new Msg(content, index%2);
26                     msgList.add(msg);
27                     adapter.notifyDataSetChanged(); // 当有新消息时,刷新ListView中的显示
28                     msgListView.setSelection(msgList.size()); // 将ListView定位到最后一行
29                     inputText.setText(""); // 清空输入框中的内容
30                 }
31             }
32         });
33     }
34
35     private void initMsgs() {
36         Msg msg1 = new Msg("娘子?", Msg.TYPE_RECEIVED);
37         msgList.add(msg1);
38         Msg msg2 = new Msg("啊哈?", Msg.TYPE_SENT);
39         msgList.add(msg2);
40     }
41 }

  在 initMsgs()方法中我们先初始化了几条数据用于在 ListView 中显示。然后在发送按钮的点击事件里获取了 EditText中的内容, 如果内容不为空则创建出一个新的 Msg 对象, 并把它添加到 msgList列表中去。之后又调用了适配器的 notifyDataSetChanged()方法,用于通知列表的数据发生了变化,这样新增的一条消息才能够在 ListView 中显示。接着调用 ListView的 setSelection()方法将显示的数据定位到最后一行,以保证一定可以看得到最后发出的一条消息。最后调用 EditText的 setText()方法将输入的内容清空。另外,我们加上一个标志index,这样就能轮流发送和接受信息了。

  最后我们的程序运行如下:

  

  //End.

  

时间: 2024-10-27 04:52:21

Android学习笔记(十二)——实战:制作一个聊天界面的相关文章

Android学习笔记(二)——探究一个活动

//此系列博文是<第一行Android代码>的学习笔记,如有错漏,欢迎指正! 活动(Activity)是最容易吸引到用户的地方了,它是一种可以包含用户界面的组件,主要用于和用户进行交互.一个应用程序中可以包含零个或多个活动.活动是Android四大组件之一,下面我们来探究一个活动. 1.创建一个活动: 我们可以按照学习笔记(一)中的流程创建了一个活动,创建之后可以看见IDE已经为我们写好的默认onCreate()方法: 默认onCreate()方法非常简单,就是调用了父类的 onCreate(

Android学习笔记十二.深入理解LauncherActvity 之LauncherActivity、PreferenceActivity、PreferenceFragment

深入理解LauncherActvity 之LauncherActivity.PreferenceActivity.PreferenceFragment 从下图我们可以知道,LauncherActivity.PreferanceActivity均继承于ListActivity,其中LauncherActivity实现当列表界面列表项被点击时所对应的Acitvity被启动:PreferanceActivity实现一个程序参数设置.存储功能的Activity列表界面. 一.LauncherActivi

【转】 Pro Android学习笔记(二二):用户界面和控制(10):自定义Adapter

目录(?)[-] 设计Adapter的布局 代码部分 Activity的代码 MyAdapter的代码数据源和构造函数 MyAdapter的代码实现自定义的adapter MyAdapter的代码继续探讨BaseAdapter 我们可以同继承抽象类BaseAdapter来实现自己的Adapter,自己设置子View的UI,不同子View可以由不同的布局,并自己进行数据和子view中数据的对应关系.图是例子的呈现结果,我们有很多图标,对这些图标按一定大小进行缩放,然后布局在GridView中.这个

Swift学习笔记十二:下标脚本(subscript)

下标脚本就是对一个东西通过索引,快速取值的一种语法,例如数组的a[0].这就是一个下标脚本.通过索引0来快速取值.在Swift中,我们可以对类(Class).结构体(structure)和枚举(enumeration)中自己定义下标脚本的语法 一.常规定义 class Student{ var scores:Int[] = Array(count:5,repeatedValue:0) subscript(index:Int) -> Int{ get{ return scores[index];

《Hibernate学习笔记十二》学生、课程、分数关系的设计与实现

<Hibernate学习笔记十二>学生.课程.分数关系的设计与实现 这个马士兵老师的Hibernate视频学习的一个题目,这里面要用到多对多.多对一的关联关系以及联合主键,因此觉得挺好的,自己写篇博文来记录下. 先考虑数据库表 1.学生表:为简单起见,只考虑了学生id和学生姓名,其中id为主键 2.课程表:为简单起见,只考虑了课程id和课程名称,其中id为主键 3.分数表 分数表有两种解决方案 3.1 第一种为:使用联合主键:student_id 和 course_id 3.2 第二种:不使用

Android学习笔记(二)--iparty登陆界面

打开应用,判断是否第一次使用. 1 private void beforeInitMenu() { 2 AppContext appContext = (AppContext) getApplicationContext(); 3 4 if (appContext.isFirstLogin()) { 5 // 第一次启动 6 //如果第一次启动,出现5张引导图片. 7 Intent intent = new Intent(this, GuideActivity.class); 8 startAc

虚拟机VMWare学习笔记十二 - 将物理机抓取成虚拟机

1. 安装VMware vCenter Converter Standalone Client 运行虚拟机,File -- Virtualize a Physical Machine 这时如果电脑中没有VMware vCenter Converter Standalone Client ,则会进行安装. 安装过程 之后图标会出现在桌面上,双击运行 选择连接到本地服务器,登陆 点击转换计算机 这个,可以将本地计算机抓取成虚拟机,也可以将其他可以访问的计算机(需知道管理员用户名及密码)抓取成虚拟机.

Android学习笔记(二):搭建安卓开发环境

① 下载 JDK 5 or JDK 6 (JRE alone is not sufficient) ->安装->设置环境变量JAVA_HOME CLASSPATH path 下载地址:Download JDK ② 下载 Eclipse 3.3 (Europa), 3.4 (Ganymede) IDE for JAVA-> 解压 下载地址:Eclipse for JAVA developer ③ 下载 Android SDK 解压-> path 里加入 SDK 包中的 tools 目

laravel3学习笔记(十二)

原作者博客:ieqi.net ==================================================================================================== 请求反射 HTTP 协议本身是无状态性的,但是在应用中处理各种业务逻辑时我们必须要有状态的把控,这样,折中的办法就是将状态进行标记然后嵌入到 HTTP 协议的请求中,然后应用根据这些标记来进行状态的串联以及处理.所以我们就要对请求进行反射处理以获取请求信息, Lara