情景描述:当Activity的布局中有RecyclerView,ListView等列表控件时,软件盘弹出会将底部控件顶起,这时底部控件可能遮挡住一些我们想要显示的内容,如下图所示,输入框就被遮挡住了,这肯定不是我们想要的结果。
解决方案:这里提供两种解决方案。(只需要使用其中一种即可)
1. 在AndroidManifest文件中,给当前Activity配置android:windowSoftInputMode="adjustPan|stateHidden"属性。
作用:adjustPan 软件弹出布局自适应,stateHidden 进入页面时隐藏软键盘(不需要隐藏的话可以不设置该值)
此种方式当软键盘弹出时,布局会整体向上移动,且不可滑动。效果图如下:
2. 监听软键盘的显示和隐藏,当软键盘显示时隐藏底部控件,当软件盘隐藏时显示底部控件。此种方式当软键盘弹出时,NestedScrollView之上的内容不会移动(例如图中的ActionBar和TextView),NestedScrollView中的内容会向上移动,且NestedScrollView中的内容可滑动。效果图如下:
键盘监听源码:
Java版:
package com.lct.softkeyboard;
import android.app.Activity;
import android.graphics.Rect;
import android.view.View;
import android.view.ViewTreeObserver;
/**
* Author:SkySmile
* Date:2018/11/6
* Description:软键盘显示与隐藏的监听
*/
public class SoftKeyBoardUtil {
//纪录根视图的显示高度
private static int rootViewVisibleHeight;
public static void addOnSoftKeyBoardListener(Activity activity,
final OnSoftKeyBoardListener listener) {
//activity的根视图
final View rootView = activity.getWindow().getDecorView();
//监听视图树中全局布局发生改变或者视图树中的某个视图的可视状态发生改变
rootView.getViewTreeObserver().addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
//获取当前根视图在屏幕上显示的大小
Rect rect = new Rect();
rootView.getWindowVisibleDisplayFrame(rect);
int visibleHeight = rect.height();
if (rootViewVisibleHeight == 0) {
rootViewVisibleHeight = visibleHeight;
return;
}
//根视图显示高度没有变化,可以看作软键盘显示/隐藏状态没有改变
if (rootViewVisibleHeight == visibleHeight) {
return;
}
//根视图显示高度变小超过200,可以看作软键盘显示了
if (rootViewVisibleHeight - visibleHeight > 200) {
listener.keyBoardShow();
rootViewVisibleHeight = visibleHeight;
return;
}
//根视图显示高度变大超过200,可以看作软键盘隐藏了
listener.keyBoardHide();
rootViewVisibleHeight = visibleHeight;
}
});
}
public interface OnSoftKeyBoardListener {
void keyBoardShow();
void keyBoardHide();
}
}
Kotlin版:
/**
* 软件盘隐藏||显示的监听
*/
fun Activity.setOnSoftKeyBoardListener(listener: OnSoftKeyBoardChangeListener) {
//activity的根视图
val rootView = window.decorView
//纪录根视图的显示高度
var rootViewVisibleHeight = 0
//监听视图树中全局布局发生改变或者视图树中的某个视图的可视状态发生改变
rootView.viewTreeObserver.addOnGlobalLayoutListener {
//获取当前根视图在屏幕上显示的大小
val rect = Rect()
rootView.getWindowVisibleDisplayFrame(rect)
val visibleHeight = rect.height()
if (rootViewVisibleHeight == 0) {
rootViewVisibleHeight = visibleHeight
return@addOnGlobalLayoutListener
}
//根视图显示高度没有变化,可以看作软键盘显示/隐藏状态没有改变
if (rootViewVisibleHeight == visibleHeight) {
return@addOnGlobalLayoutListener
}
//根视图显示高度变小超过200,可以看作软键盘显示了
if (rootViewVisibleHeight - visibleHeight > 200) {
listener.keyBoardShow()
rootViewVisibleHeight = visibleHeight
return@addOnGlobalLayoutListener
}
//根视图显示高度变大超过200,可以看作软键盘隐藏了
listener.keyBoardHide()
rootViewVisibleHeight = visibleHeight
return@addOnGlobalLayoutListener
}
}
interface OnSoftKeyBoardChangeListener {
fun keyBoardShow()
fun keyBoardHide()
}
使用方法(这里只给出了java版的调用方式。kotlin版的调用也很简单,因为定义为了Activity的扩展函数,所以在Activity中直接调用setOnSoftKeyBoardListener即可):
package com.lct.softkeyboard;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
/**
* 当Activity的布局中有RecyclerView,ListView等列表控件时,软件盘弹出会将底部控件顶起。
* 这里总结两种解决方式:
* 1.在AndroidManifest文件中,给当前Activity配置android:windowSoftInputMode="adjustPan|stateHidden"属性,
* 作用:adjustPan 软件弹出布局自适应,stateHidden 进入页面时隐藏软键盘(不需要隐藏的话可以不设置该值)
* 此种方式当软键盘弹出时,布局会整体向上移动,且不可滑动
* <p>
* 2.监听软键盘的显示和隐藏,当软键盘显示时隐藏底部控件,当软件盘隐藏时显示底部控件
* 此种方式当软键盘弹出时,NestedScrollView之上的内容不会移动,NestedScrollView中的内容会向上移动,
* 且NestedScrollView中的内容可滑动
*/
public class MainActivity extends AppCompatActivity {
private Button btnBottom;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnBottom = findViewById(R.id.btn_bottom);
//软键盘监听事件
SoftKeyBoardUtil.addOnSoftKeyBoardListener(this,
new SoftKeyBoardUtil.OnSoftKeyBoardListener() {
@Override
public void keyBoardShow() {
//软键盘弹出,隐藏底部控件
btnBottom.setVisibility(View.INVISIBLE);
}
@Override
public void keyBoardHide() {
//软键盘消失,显示底部控件
btnBottom.setVisibility(View.VISIBLE);
}
});
}
}
activity_main.xml文件
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/tv_top"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="NestedScrollView之上的内容" />
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/tv_top">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/tv"
android:layout_width="match_parent"
android:layout_height="230dp"
android:paddingTop="20dp"
android:text="NestedScrollView中的测试填充内容,高度设置为230dp是为了使键盘弹出时遮住输入框" />
<EditText
android:id="@+id/et"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/tv"
android:hint="测试输入框" />
<!--当布局中有RecyclerView,ListView等列表控件时,软件盘弹出时会顶起底部控件-->
<!--此处添加的RecyclerView,只是为了展示效果-->
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/et" />
</RelativeLayout>
</android.support.v4.widget.NestedScrollView>
<Button
android:id="@+id/btn_bottom"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:text="被顶起的底部控件" />
</RelativeLayout>