通过WindowInsets监听软键盘状态

如果不了解状态栏、Windows Insets相关的内容,可以先看下这篇文章

一般情况下,对于需要软键盘的页面,我们会用adjustResize让软键盘弹出时系统自动Resize我们的页面,如果想判断软键盘的高度,需要通过监听最外层布局的大小来间接判断,但如果我们想自己处理,或监听下软键盘的状态,就需要用一些其他方法了,而Window Insets就正好可以达成这个目标。

首先,Activity的windowSoftInputMode仍需设置为adjustResize

然后,通过SYSTEM UI改变当软键盘弹出时系统对Activity布局的处理方式。

1
2
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE);

如果了解System UI的话,就知道通过上面的设置后,系统不给我们处理状态栏了,我们的Activity顶部的内容被状态栏遮住一部分,这时就要自己处理Window Insets做偏移。

1
2
3
4
5
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.activity_main), new OnApplyWindowInsetsListener() {
@Override
public WindowInsetsCompat onApplyWindowInsets(View view, WindowInsetsCompat windowInsetsCompat) {
view.setPadding(0,windowInsetsCompat.getSystemWindowInsetTop(),
0, windowInsetsCompat.getSystemWindowInsetBottom());

通过OnApplyWindowInsetsListener,我们拿到了系统的Window Insets的大小,假设R.id.activity_main是Activity的根布局,把SystemWindowInsetTop设置为它的padding,我们的页面就可以正常显示了,跟没设置SYSTEM UI时一样。

设置这个SYSTEM UI后,状态栏系统不帮我们处理了,SystemWindowInsetTop就是状态栏的高度,与此同时,虽然我们设置了adjustResize的windowSoftInputMode,但是系统也没再在软键盘弹出时帮我们Resize Activity布局的大小了。

开头提到的文章介绍View.SYSTEM_UI_FLAG_LAYOUT_STABLE时说了,正常情况下状态栏显示隐藏,软键盘弹出隐藏时,系统会Resize我们Activity的布局,但当设置了这个Flag后,系统不对我们的布局进行Resize了,Activity布局的大小是不变的,也就是”Stable”的,当SatusBar或软键盘出现/隐藏需要页面做适配时,就通过Window Insets告诉我们需要适配的区域大小是多少,所以在之前的代码中,我们不只设置了activity_main的padding_top,还同时设置了padding_bottom,这样当软键盘弹出或隐藏时,Activity的布局就可以像正常的adjustResize一样做适配。

所以,通过Window Insets,我们就可以通过SystemWindowInsetBottom的大小来判断软键盘是弹出还是隐藏了。

另外,由于不是adjustResize默认的粗暴式Resize,页面适配的工作完全由我们自己做了,我们就可以记录软键盘高度,页面适配时做个动画让页面更流畅点什么的。