類似QQ聊天介面
現在越來越多的手機軟體具備社交聊天功能,所以聊天介面的使用便變得很頻繁,下面我們將自己實現一個簡單的類似QQ的聊天介面。
首先來看整個工程的目錄結構:
目錄結構很簡單,主要難點在Adapter。
然後看實現的效果圖:
從效果圖上看出,介面底部用了一個EditText和一個Button,水平分佈,上面放了一個RecyclerView,佈局程式碼如下:
<?xml version="1.0" encoding="utf-8"?>
<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:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:background="#ede9e9"
android:orientation="vertical"
tools:context="com.demo.sisyphus.hellorobot.MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="機器人"
android:textSize="10pt"
android:gravity="center_horizontal"/>
<android.support.v7.widget.RecyclerView
android:id="@+id/rv_chat"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_alignParentBottom="true">
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/rect"
android:layout_weight="1"
android:layout_marginRight="5dp"
android:id="@+id/et_msg"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/btn_send"
android:text="@string/btnsend"/>
</LinearLayout>
</LinearLayout>
然後看這篇文章的重點Adapter,用過RecyclerView的都知道,它的資料處理都在Adapter,類似ListView的Adapter,但是更加強大,程式碼如下:
public class ChatAdapter extends RecyclerView.Adapter {
private Context context;
private static final int ME = 0;
private static final int OTHRE = 1;
private List<Msg> list = new ArrayList<>();
public ChatAdapter(Context context, ArrayList<Msg> list){
this.context = context;
this.list = list;
}
class ViewHolder extends RecyclerView.ViewHolder {
LinearLayout me;
LinearLayout other;
public ViewHolder(View itemView) {
super(itemView);
me = (LinearLayout) itemView.findViewById(R.id.me);
other = (LinearLayout) itemView.findViewById(R.id.other);
}
public LinearLayout getMe() {
return me;
}
public LinearLayout getOther() {
return other;
}
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
ViewHolder viewHolder = null;
switch (viewType){
case ME:
viewHolder = new ViewHolder(LayoutInflater.from(context).inflate(R.layout.chat_item2, parent, false));
break;
case OTHRE:
viewHolder = new ViewHolder(LayoutInflater.from(context).inflate(R.layout.chat_item, parent, false));
break;
}
return viewHolder;
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
ViewHolder viewHolder = (ViewHolder) holder;
TextView tv = new TextView(context);
Msg msg = list.get(position);
tv.setText(msg.getMsg());
switch (msg.getType()){
case ME:
/**
* 當recyclerview承載的資料過多的時候,去滑動recyclerview,
* 劃出螢幕以外的item會重新繫結資料,如果這個時候繫結資料的方式是
* viewgroup的addView()方法的話,會出現item新增很多重複的view
* 所以這之前應該執行清除裡面view的操作,即removeAllViews()
*/
viewHolder.getMe().removeAllViews();
tv.setBackgroundResource(R.mipmap.chat_me);
viewHolder.getMe().addView(tv);
break;
case OTHRE:
viewHolder.getOther().removeAllViews();
tv.setBackgroundResource(R.mipmap.chat_other);
viewHolder.getOther().addView(tv);
break;
}
}
@Override
public int getItemCount() {
return list.size();
}
@Override
public int getItemViewType(int position) {
return list.get(position).getType() == 0 ? ME : OTHRE;
}
public void addMsg(Msg msg){
list.add(msg);
}
}
因為是聊天介面,所以需要RecyclerView根據發出訊息的人是誰來判斷這條訊息是顯示左邊還是右邊,因此就需要根據ViewType的值來載入兩個不同的佈局檔案,在這個專案中分別是chat_item.xml和chat_item2.xml。而訊息和訊息型別的判斷我們封裝成一個物件,即Msg類:
public class Msg {
private String msg;
private int type;
public Msg(String msg, int type){
this.msg = msg;
this.type = type;
}
public String getMsg() {
return msg;
}
public int getType() {
return type;
}
}
這個類只有兩個屬性,很簡單,主要承載訊息內容和訊息型別(來自誰),訊息內容可根據實際需要擴充套件為圖片、音訊之類的。
最後在Activity裡面,將所有控制元件初始化之後,我們就實現了這個簡單的聊天介面。
另外,為了使這個聊天介面聊天介面更加具有可用性,我們可以給訊息加上定位的效果,即當訊息過多時,RecyclerView自動滑動到當前訊息的位置,使用RecyclerView的smoothScrollToPosition(position)方法即可實現,很簡單。
最後補充兩個點:
**1. 圓形頭像
這個圓形頭像使用了一個開源庫RoundedImageView
android studio直接在專案上右鍵-Open Module Settings-Dependencies-Add Library dependency,直接搜尋RoundedImageView就可以了,選擇最新版本。
使用很簡單,引入RoundedImageView控制元件,設定其屬性就可以得到多種形狀的圖片了。
2. 我做這個專案遇到的一個問題
在做這個Demo時,我發現,當聊天資料量達到十多條時,滑動RecyclerView,一些item會一直重複新增資料項,後來我發現是繫結資料的時候沒有考慮周全,出現問題的地方就是我Adapter寫註釋的地方,原因和解決辦法可以參考註釋。
好了,一個簡單的聊天介面就大功告成,感興趣的朋友可以點選這裡下載原始碼,我放在github上的。
可能還有很多程式碼Bug和說明不正確的地方,請批評指正。**