今天參考書上的例子,自己也實現了一個相對美觀的聊天界面,過程如下:
一、第一步制作用於顯示聊天內容的圖片,使用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>
三、新建消息實體類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 }
四、由於消息是用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 }
五、最后來實現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 }
至此,此次實戰結束,運行效果圖:


