类似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和说明不正确的地方,请批评指正。**

猜你喜欢

转载自blog.csdn.net/qq_26525715/article/details/59484763