今天看郭霖《第一行代码》书上写了一个聊天窗体的小例子,自己就练习学了一下。加上一些自己的理解整理了一下。
1.第一步首先是制作9.patch图片,这个在android sdk 目录下tools文件,找到draw9patch.bat文件双击打开。这是一个专门用来处理安卓里面图像的小工具,你可以对图片指定拉伸的效果,具体教程可以百度,很简单的。
2.编写主界面
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:background="#d8e0e8" android:orientation="vertical"><ListView android:id="@+id/msg_list_view"android:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="1"android:divider="#0000"></ListView><LinearLayout android:layout_width="match_parent"android:layout_height="wrap_content"><EditText android:id="@+id/input_text"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:hint="Typ something in here"android:maxLines="2"/><Button android:id="@+id/send"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="send"/></LinearLayout>
</LinearLayout>
主界面里我们可以看到有一个ListView用于加载信息,线性布局进行嵌套,里层里有一个编辑框和一个按钮。下图就是布局初步效果图:
3.编写ListView子项布局,新建一个布局文件
<span style="font-size:12px;"><?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical" android:padding="10dp"><LinearLayout android:id="@+id/left_layout"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="left"android:background="@drawable/message_left"><TextView android:id="@+id/left_msg"android:layout_width="wrap_content"android:layout_height="wrap_content"android:gravity="center"android:layout_margin="10dp"android:textColor="#fff"/></LinearLayout><LinearLayout android:id="@+id/right_Layout"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="right"android:background="@drawable/message_right"><TextView android:id="@+id/right_msg"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:layout_margin="10dp"/> </LinearLayout>
</LinearLayout></span>
这里最外层是线性布局,里边嵌套两个线性布局。这两个布局分别是给消息发送界面和消息接收界面。后面可以通过设置布局的显示和隐藏属性来显示我们需要的消息。这和我之前学贪吃蛇的布局挺像的,就像把一开始的游戏前出现界面和游戏的场景界面设置在一个布局文件很相似。这也是最近学习布局收获的一点,光学课本上的单个布局的特点没有应用到实际的应用里边,很难自己想象原来布局可以这样灵活。
效果图如下:
3.完成MainActivity.java,写好布局文件以后开始写代码,这里需要大概写的几点是:
1.定义消息类的实体类Msg
public class Msg{ }
里面需要设置消息的类型:发送,接收,内容。
2.ListView适配器的建立
首先它需要继承ArrayAdapter,将泛型指定为Msg类。
这里运用到了很多书上说的ListView的优化,通过if_else判断,如果convertView为空就重新初始化加载布局,这时就需要加载很多东西,如果convertView不为空时,说明它之前有缓存,可以重用,那我们直接调用它,就大大提高了运行的效率。
还有通过创建ViewHolder这个内部类,可以对控件的实例进行缓存。当convertView为空时。将控件的实例存在ViewHolder里,调用setTag()方法,将ViewHolder对象存储在View里。当ViewHolder不为空时,调用View的setTag()方法,重新取出ViewHolder。这样就不用每次调用findViewById()方法获取控件。
3.收发消息布局的隐藏和显示
通过判断消息的类型,进行设置显示和隐藏消息。
if(msg.getType()==Msg.RECEIVED){
//如果是收到的消息,则显示左边消息布局,将右边消息布局隐藏
viewHolder.leftLayout.setVisibility(View.VISIBLE);
viewHolder.rightLayout.setVisibility(View.GONE);
viewHolder.leftMsg.setText(msg.getContent());
}else if(msg.getType()==Msg.SENT){
//如果是发出去的消息,显示右边布局的消息布局,将左边的消息布局隐藏
viewHolder.rightLayout.setVisibility(View.VISIBLE);
viewHolder.leftLayout.setVisibility(View.GONE);
viewHolder.rightMsg.setText(msg.getContent());
}
4.初始化消息initMsg()
写几条消息测试一下首发消息是否正确。
5.给按钮send设置监听器事件
这里用到的是send.setOnClickListener(new OnClickListener(){ },这一看就是匿名内部类的方式。
这里只是大体说了一下编写的大概内容,具体的可以看下面源代码:
package com.example.chat_layout;import java.util.ArrayList;
import java.util.List;import android.R.string;
import android.os.Bundle;
import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.Adapter;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;public class MainActivity extends Activity {private ListView msgListView;private EditText inputText;private Button send;private MsgAdapter adapter;private List<Msg> msgList = new ArrayList<Msg>();@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);requestWindowFeature(Window.FEATURE_NO_TITLE);//设置窗口没有标题栏setContentView(R.layout.activity_main);initMsg();adapter = new MsgAdapter(MainActivity.this, R.layout.msg_item, msgList);inputText = (EditText) findViewById(R.id.input_text);send = (Button) findViewById(R.id.send);msgListView = (ListView) findViewById(R.id.msg_list_view);msgListView.setAdapter(adapter);send.setOnClickListener(new OnClickListener(){@Overridepublic void onClick(View v) {String content = inputText.getText().toString();if(!"".equals(content)){Msg msg = new Msg(content, Msg.SENT);msgList.add(msg);adapter.notifyDataSetChanged();//有新消息时,刷新ListView中的显示msgListView.setSelection(msgList.size());//将ListView定位到最后一行inputText.setText("");//清空输入框的内容}}});}private void initMsg() {Msg msg1 = new Msg("I miss you!",Msg.RECEIVED);msgList.add(msg1);Msg msg2 = new Msg("I miss you,too!",Msg.SENT);msgList.add(msg2);Msg msg3 = new Msg("I will come back soon!",Msg.RECEIVED);msgList.add(msg3);}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {// Inflate the menu; this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.main, menu);return true;}public class Msg{public static final int RECEIVED = 0;//收到一条消息public static final int SENT = 1;//发出一条消息private String content;//消息的内容private int type;//消息的类型public Msg(String content,int type){this.content = content;this.type = type;}public String getContent(){return content;}public int getType(){return type;}}public class MsgAdapter extends ArrayAdapter<Msg>{private int resourceId;public MsgAdapter(Context context, int textViewresourceId, List<Msg> objects) {super(context, textViewresourceId, objects);resourceId = textViewresourceId;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {Msg msg = getItem(position);View view;ViewHolder viewHolder;if(convertView == null){view = LayoutInflater.from(getContext()).inflate(resourceId, null);viewHolder = new ViewHolder();viewHolder.leftLayout = (LinearLayout)view.findViewById(R.id.left_layout);viewHolder.rightLayout = (LinearLayout)view.findViewById(R.id.right_Layout);viewHolder.leftMsg = (TextView)view.findViewById(R.id.left_msg);viewHolder.rightMsg = (TextView)view.findViewById(R.id.right_msg);view.setTag(viewHolder);}else{view = convertView;viewHolder = (ViewHolder) view.getTag();}if(msg.getType()==Msg.RECEIVED){//如果是收到的消息,则显示左边消息布局,将右边消息布局隐藏viewHolder.leftLayout.setVisibility(View.VISIBLE);viewHolder.rightLayout.setVisibility(View.GONE);viewHolder.leftMsg.setText(msg.getContent());}else if(msg.getType()==Msg.SENT){//如果是发出去的消息,显示右边布局的消息布局,将左边的消息布局隐藏viewHolder.rightLayout.setVisibility(View.VISIBLE);viewHolder.leftLayout.setVisibility(View.GONE);viewHolder.rightMsg.setText(msg.getContent());}return view;}class ViewHolder{LinearLayout leftLayout;LinearLayout rightLayout;TextView leftMsg;TextView rightMsg;}}}
最后效果图:可以看到除了程序中初始化的3条消息,ok这是通过底下编辑器输入的,看一看到实现了聊天对话框的基本内容和要求。