解决RecyclerView实现聊天界面,但点击下面的EditText后弹出的输入法会遮盖RecyclerView内容的方法

学习Android也将近4个年头了,一直想写点自己所学的内容来帮助后来人,为互联网奉献自己的一份力量,也算自己的积累。但是之前由于自己的惰性一直没有下笔,那就从今天这一篇开始吧!


我们做Android开发经常会有做即时聊天的需求,产品经理不管做啥APP,都要塞个IM,那就算是扯上社交了。我今天要讲的就是如何实现Android聊天界面。可能听到这个,在看文章的你就准备关闭网页了然后开喷了,但请别急,我写这篇文章自然有写这篇文章的道理。


1、首先我们创建项目,写好布局。布局比较简单,上面是个RecyclerView,用来显示聊天的对话。下面一个水平布局的LinearLayout,里面一个EditText作为文本编辑框,一个Button用来发送。这样布局就算写好了。

<?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.support.v7.widget.RecyclerView
        android:id="@+id/recyclerView_chat"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:overScrollMode="never"
        android:scrollbars="vertical"/>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="55dp"
        android:orientation="horizontal">
        <EditText
            android:id="@+id/editText_message"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="match_parent"
            android:hint="输入消息内容"
            android:padding="10dp" />
        <Button
            android:id="@+id/btn_send"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:text="发送" />
    </LinearLayout>
</LinearLayout>

2、我们在MainActivity里面初始化一下布局,同样也非常的简单。

package com.liuxiaoyi.chatdemo;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.widget.Button;
import android.widget.EditText;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {
    private RecyclerView recyclerView_chat;
    private EditText editText_message;
    private Button btn_send;

    private ChatAdapter chatAdapter;
    private ArrayList<Chat> chatArrayList = new ArrayList<>();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        recyclerView_chat = (RecyclerView) findViewById(R.id.recyclerView_chat);
        editText_message = (EditText) findViewById(R.id.editText_message);
        btn_send = (Button) findViewById(R.id.btn_send);

        chatArrayList.add(new Chat("你好啊。",ChatAdapter.TYPE_SEND));
        chatArrayList.add(new Chat("你叫什么名字啊?",ChatAdapter.TYPE_SEND));
        chatArrayList.add(new Chat("你好,我叫小丽",ChatAdapter.TYPE_RECEIVE));
        chatArrayList.add(new Chat("你是哪里人啊?",ChatAdapter.TYPE_SEND));
        chatArrayList.add(new Chat("我是湖南长沙人",ChatAdapter.TYPE_RECEIVE));
        chatArrayList.add(new Chat("好巧啊,我也是长沙的",ChatAdapter.TYPE_SEND));
        chatArrayList.add(new Chat("咱们真有缘分诶",ChatAdapter.TYPE_SEND));
        chatArrayList.add(new Chat("我也觉得呢",ChatAdapter.TYPE_RECEIVE));

        chatAdapter = new ChatAdapter(MainActivity.this,chatArrayList);
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(MainActivity.this);
        recyclerView_chat.setLayoutManager(linearLayoutManager);
        recyclerView_chat.setAdapter(chatAdapter);
    }

}

3、构造一下聊天实体

package com.liuxiaoyi.chatdemo;

public class Chat {
    private String chatContent;
    private int type;

    public Chat(String chatContent, int type) {
        this.chatContent = chatContent;
        this.type = type;
    }

    public String getChatContent() {
        return chatContent;
    }

    public void setChatContent(String chatContent) {
        this.chatContent = chatContent;
    }

    public int getType() {
        return type;
    }

    public void setType(int type) {
        this.type = type;
    }
}

4、最后写好适配器

package com.liuxiaoyi.chatdemo;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import java.util.ArrayList;

public class ChatAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{
    public static final int TYPE_SEND = 0;
    public static final int TYPE_RECEIVE = 1;

    private Context context;
    private ArrayList<Chat> chatArrayList = new ArrayList<>();

    public ChatAdapter(Context context,ArrayList<Chat> chatArrayList){
        this.context = context;
        this.chatArrayList = chatArrayList;
    }

    @Override
    public int getItemViewType(int position) {
        if(chatArrayList.get(position).getType() == TYPE_SEND){
            return TYPE_SEND;
        }else if(chatArrayList.get(position).getType() == TYPE_RECEIVE){
            return TYPE_RECEIVE;
        }else {
            return super.getItemViewType(position);
        }
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view;
        if(viewType==TYPE_SEND){
            view = LayoutInflater.from(context).inflate(R.layout.item_send,parent,false);
            return new SendViewHolder(view);
        }else {
            view = LayoutInflater.from(context).inflate(R.layout.item_receive,parent,false);
            return new ReceiveViewHolder(view);
        }
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        if(holder instanceof SendViewHolder){
            SendViewHolder viewHolder = (SendViewHolder) holder;
            viewHolder.textView_send.setText(chatArrayList.get(position).getChatContent());
        }else if(holder instanceof ReceiveViewHolder){
            ReceiveViewHolder viewHolder = (ReceiveViewHolder) holder;
            viewHolder.textView_receive.setText(chatArrayList.get(position).getChatContent());
        }
    }

    @Override
    public int getItemCount() {
        return chatArrayList.size();
    }

    private class SendViewHolder extends RecyclerView.ViewHolder{
        private TextView textView_send;
        public SendViewHolder(View itemView) {
            super(itemView);
            textView_send = (TextView) itemView.findViewById(R.id.textView_send);
        }
    }

    private class ReceiveViewHolder extends RecyclerView.ViewHolder{
        private TextView textView_receive;
        public ReceiveViewHolder(View itemView) {
            super(itemView);
            textView_receive = (TextView) itemView.findViewById(R.id.textView_receive);

        }
    }
}

这样也就算完工了。我们看一下效果。


感觉好像不错,是这么个意思。这时候我们心里就在暗自庆幸,聊天界面也不过如此嘛,做出微信这样的APP也太简单了,老子天下代码水平天下第一。


但是稍微点击一下,我们就会发现问题。我们看图


当我们点击EditText的时候,键盘弹了出来。但是他好像和微信QQ又那么一点点不一样,微信QQ的聊天框弹出之后,键盘是不会遮住聊天内容的。


这怎么能难倒我们呢?网上搜一下解决方案不就可以了么?于是我们开始上网搜。

网上给出的方法总得来说有两种。

第一种:首先在清单文件中的Activity节点增加android:windowSoftInputMode="adjustResize"这么一句话,然后

LinearLayoutManager manager = new LinearLayoutManager(context);
manager.setStackFromEnd(true);
recyclerView.setLayoutManager(manager);

好的,马上修改清单文件为

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.liuxiaoyi.chatdemo" >

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme" >
        <activity android:name=".MainActivity"
            android:windowSoftInputMode="stateHidden|adjustResize">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
MainActivity修改为

package com.liuxiaoyi.chatdemo;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.widget.Button;
import android.widget.EditText;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {
    private RecyclerView recyclerView_chat;
    private EditText editText_message;
    private Button btn_send;

    private ChatAdapter chatAdapter;
    private ArrayList<Chat> chatArrayList = new ArrayList<>();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        recyclerView_chat = (RecyclerView) findViewById(R.id.recyclerView_chat);
        editText_message = (EditText) findViewById(R.id.editText_message);
        btn_send = (Button) findViewById(R.id.btn_send);

        chatArrayList.add(new Chat("你好啊。",ChatAdapter.TYPE_SEND));
        chatArrayList.add(new Chat("你叫什么名字啊?",ChatAdapter.TYPE_SEND));
        chatArrayList.add(new Chat("你好,我叫小丽",ChatAdapter.TYPE_RECEIVE));
        chatArrayList.add(new Chat("你是哪里人啊?",ChatAdapter.TYPE_SEND));
        chatArrayList.add(new Chat("我是湖南长沙人",ChatAdapter.TYPE_RECEIVE));
        chatArrayList.add(new Chat("好巧啊,我也是长沙的",ChatAdapter.TYPE_SEND));
        chatArrayList.add(new Chat("咱们真有缘分诶",ChatAdapter.TYPE_SEND));
        chatArrayList.add(new Chat("我也觉得呢",ChatAdapter.TYPE_RECEIVE));

        chatAdapter = new ChatAdapter(MainActivity.this,chatArrayList);
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(MainActivity.this);
        linearLayoutManager.setStackFromEnd(true);
        recyclerView_chat.setLayoutManager(linearLayoutManager);
        recyclerView_chat.setLayoutManager(linearLayoutManager);
        recyclerView_chat.setAdapter(chatAdapter);
    }
}

运行起来。大神诚不欺我啊,果然可以滚动了。聊天界面也不过如此嘛,做出微信这样的APP也太简单了,老子天下代码水平天下第一。

又稍微点击一下,又发现了问题

开始的界面是这样子的

点击聊天框后变成了这样


发现问题没有?微信QQ点击之后是滚动到底部,而不是只滚动到这一页的底部的哪一个item啊,这不是坑人嘛。唉,大神居然也会欺骗我,世态炎凉啊。

第一种方法不行 我们看第二种方法:

1、设置RecyclerView.scrollToPosition(list.size() - 1);

2、设置mLayoutManager.setStackFromEnd(true);

3、RecyclerView用ScrollView包裹起来,然后获取屏幕的高度和键盘的高度,计算出ScrollView需要滑动到的位置。


大神你不是骗我吧,前面我还能理解,用ScrollView包裹RecyclerView????(此处黑人脸问号),这干嘛还用RecyclerView,直接ScrollView里面add子view不就好了么。

这种方案我就不试了,如果在看文章的你有兴趣,可以尝试一下。


好了,文章写到这里就结束了,拜拜。


当然没有啦,我还没有提出解决方案。接下来看我的。(此处柯南背景音乐),新几子哇,一次莫黑一多次。

首先我们仔细看一下微信和QQ的实现方案,它的方案是不管我当前在RecyclerView 的哪个位置,只要点击输入框,就会跳回最后一条消息的位置。那我们只需要在我们点击输入框的时候滚到最后一个位置就可以了。思路就是这样,非常的简单。

接下来我们就上手实现

布局文件修改如下:

<?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.support.v7.widget.RecyclerView
        android:id="@+id/recyclerView_chat"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:overScrollMode="never"
        android:scrollbars="vertical"/>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="55dp"
        android:orientation="horizontal">
        <FrameLayout
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1">
            <EditText
                android:id="@+id/editText_message"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:hint="输入消息内容"
                android:padding="10dp" />
            <LinearLayout
                android:id="@+id/layout_edit"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:orientation="vertical"/>
        </FrameLayout>

        <Button
            android:id="@+id/btn_send"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:text="发送" />
    </LinearLayout>
</LinearLayout>


仔细看,我在EditText上增加了一个布局,用他来控制EditText的点击事件(当点击的时候,手动请求焦点)。

看MainActivity里面的操作

package com.liuxiaoyi.chatdemo;

import android.app.Activity;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.MotionEvent;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.Toast;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {
    private RecyclerView recyclerView_chat;
    private EditText editText_message;
    private Button btn_send;
    private LinearLayout layout_edit;

    private ChatAdapter chatAdapter;
    private ArrayList<Chat> chatArrayList = new ArrayList<>();

    Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what){
                case 0:
                    recyclerView_chat.scrollToPosition(chatArrayList.size()-1);
                    break;
            }
        }

    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        recyclerView_chat = (RecyclerView) findViewById(R.id.recyclerView_chat);
        editText_message = (EditText) findViewById(R.id.editText_message);
        btn_send = (Button) findViewById(R.id.btn_send);
        layout_edit = (LinearLayout) findViewById(R.id.layout_edit);

        chatArrayList.add(new Chat("你好啊。",ChatAdapter.TYPE_SEND));
        chatArrayList.add(new Chat("你叫什么名字啊?",ChatAdapter.TYPE_SEND));
        chatArrayList.add(new Chat("你好,我叫小丽",ChatAdapter.TYPE_RECEIVE));
        chatArrayList.add(new Chat("你是哪里人啊?",ChatAdapter.TYPE_SEND));
        chatArrayList.add(new Chat("我是湖南长沙人",ChatAdapter.TYPE_RECEIVE));
        chatArrayList.add(new Chat("好巧啊,我也是长沙的",ChatAdapter.TYPE_SEND));
        chatArrayList.add(new Chat("咱们真有缘分诶",ChatAdapter.TYPE_SEND));
        chatArrayList.add(new Chat("我也觉得呢",ChatAdapter.TYPE_RECEIVE));

        chatAdapter = new ChatAdapter(MainActivity.this,chatArrayList);
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(MainActivity.this);
        recyclerView_chat.setLayoutManager(linearLayoutManager);
        recyclerView_chat.setAdapter(chatAdapter);

        layout_edit.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                editText_message.requestFocus();
                showSoftInput(MainActivity.this, editText_message);
                handler.sendEmptyMessageDelayed(0,250);
            }
        });

        recyclerView_chat.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                hideSoftInput(MainActivity.this, editText_message);
                return false;
            }
        });
    }

    public static void showSoftInput(Context context, View view) {
        InputMethodManager imm = (InputMethodManager) context.getSystemService(Activity.INPUT_METHOD_SERVICE);
        imm.showSoftInput(view, InputMethodManager.SHOW_FORCED);
    }

    public static void hideSoftInput(Context context, View view) {
        InputMethodManager imm = (InputMethodManager) context.getSystemService(Activity.INPUT_METHOD_SERVICE);
        imm.hideSoftInputFromWindow(view.getWindowToken(), 0);

    }
}

我在这里获得布局文件中新增加的那个View,然后让他来给EditText请求焦点,同时用Handler的 sendEmptyMessageDelayed( 0 , 250 )方法让recyclerView等一会儿再滑动(此时弹出框已被弹出)。当RecyclerView有Touch事件的时候隐藏掉输入法,这样就可以了。


这里行文就真正结束了,有问题可以在底下留言。谢谢大家。

  • 7
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值