Android中软键盘展示、EditText焦点获取及windowSoftInputMode属性探究

时间:2023-03-08 17:03:13
Android中软键盘展示、EditText焦点获取及windowSoftInputMode属性探究

2017-08-14 21:44:23

有很多中情况,分别展示。

1、Activity不做任何设置,布局使用LinearLayout

会自动滚动EditText之上的所有View,代码:

 <?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"> <TextView
android:id="@+id/rrr"
android:layout_width="match_parent"
android:layout_height="60dp"
android:gravity="center_vertical"
android:text="这是标题"
android:textColor="#0f0980"/> <EditText
android:id="@+id/edit1"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_marginTop="10dp"
android:hint="第1个"
android:textColor="#0f0980"/> <EditText
android:id="@+id/edit2"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_marginTop="10dp"
android:hint="第2个"
android:textColor="#0f0980"/> <EditText
android:id="@+id/edit3"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_marginTop="10dp"
android:hint="第3个"
android:textColor="#0f0980"/> <EditText
android:id="@+id/edit4"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_marginTop="10dp"
android:hint="第4个"
android:textColor="#0f0980"/> <EditText
android:id="@+id/edit5"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_marginTop="10dp"
android:hint="第5个"
android:textColor="#0f0980"/> <EditText
android:id="@+id/edit6"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_marginTop="10dp"
android:hint="第6个"
android:textColor="#0f0980"/> <EditText
android:id="@+id/edit7"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_marginTop="10dp"
android:hint="第7个"
android:textColor="#0f0980"/> <EditText
android:id="@+id/edit8"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_marginTop="10dp"
android:hint="第8个"
android:textColor="#0f0980"/>
</LinearLayout>

效果图:

2、Activity不做任何设置,布局使用RelativeLayout、FrameLayout

使用RelativeLayout和FrameLayout都是一样的,会自动上划至EditText完全展示。

3、关于Focus

如果要想指定某个EditText获取焦点,需要在代码中如下调用

 mEdit8.requestFocus();

还有2个关于焦点的方法,有时候需要配合使用,如下:

 mEdit1.setFocusable(false);
mEdit1.setFocusableInTouchMode(false);
mEdit1.requestFocus();

默认是页面中第一个EditText获取焦点,如果第一个EditText不想获取焦点,则系统自动选择第二个EditText获取焦点。如果都设置不获取焦点,则都没有焦点。

需要注意的是,通过setFocus***设置为不获取焦点,点击EditText时不会获取焦点,不会弹出软键盘,所以要慎用。

4、获取焦点,并展示软键盘

不能在onCreate()方法中直接调用展示软键盘的操作,可用Handler或者点击时显示软键盘,一种方案是:

    mEdit8.postDelayed(new Runnable() {
@Override
public void run() {
InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
inputMethodManager.showSoftInput(mEdit8, InputMethodManager.SHOW_FORCED);
}
}, 100);

5、EditText不获取焦点

如果想要在进入页面时,页面中所有的EditText都不获取焦点,用户点击时才获取焦点,不好的做法如下:

     <EditText
android:id="@+id/edit1"
android:layout_width="match_parent"
android:layout_height="460dp"
android:layout_marginTop="70dp"
android:hint="第1个"
7 android:focusable="false"
8 android:focusableInTouchMode="false"
android:textColor="#0f0980"/>

这样一来,edit1就不会获得焦点,点击也无法获得焦点。比较合理的做法是在其父ViewGroup上设置,如下:

 <FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
5 android:focusable="true"
6 android:focusableInTouchMode="true"
android:orientation="vertical">

这样一来,父View获取焦点,子View就不会再获取焦点了。同时,又不影响子View在点击时获取焦点。

6、布局最外层是ScrollView

如果布局最外层是ScrollView,那么其中的EditText会获得焦点并自动弹出软键盘,前面提到过,只会自动获取焦点,这里会自动弹出软键盘。如果不想让软件盘自动弹出来,可以让第一个EditText之前的View获取焦点即可,5中提到的父View获取焦点作用其实是一样的。

简单梳理一下:

只要页面中有EditText,在没有特殊设置的情况下,EditText会自动获得焦点。如果EditText在ScrollView中,则EditText不仅会自动获得焦点,还会弹出软键盘。要想不弹出软键盘,其实很简单,让其他优先于EditText获取到焦点的View得到焦点即可。

同时以上内容均是在没有设置任何windowSoftInputMode,使用默认值stateUnspecified。

7、stateVisible

The soft keyboard is visible when that's normally appropriate (when the user is navigating forward to the activity's main window).

强制召唤软键盘,如果有获得焦点的EditText,则在EditText上弹出。

如果页面上没有EditText或者所有的EditText都不可见呢?软键盘还是会弹出来的,这种行为很怪异,需谨慎。

8、stateAlwaysVisible

The soft keyboard is made visible when the user chooses the activity — that is, when the user affirmatively navigates forward to the activity, rather than backs into it because of leaving another activity.

用户选择activity时,软键盘总是处于显示的状态,与stateVisible的区别是:stateVisible的Activity在跳转到其他Act再次返回时,软键盘不会展示,而stateAlwaysVisible则会一直处于展示状态。

9、stateUnchanged

The soft keyboard is kept in whatever state it was last in, whether visible or hidden, when the activity comes to the fore

当这个activity出现时,软键盘将一直保持在上一个activity里的状态,无论是隐藏还是显示。

如果当前Activity是第一个Activity,使用这个属性和stateUnspecified是一样的。如果上一个Activity展示软键盘,则当前Activity也会展示软键盘。

10、stateHiden

The soft keyboard is hidden when the user chooses the activity — that is, when the user affirmatively navigates forward to the activity, rather than backs into it because of leaving another activity.

用户选择activity时,软键盘总是被隐藏。但是点击EditText时又可以弹出软键盘。比如前面提到的ScrollView自动弹出软键盘,如果使用这个属性,则不会自动弹出。

11、stateAlwaysHiden

The soft keyboard is always hidden when the activity's main window has input focus.

以为应该和stateAlwaysVisible一样的,但是测试发现,跳转到其他页面回来时,即便ScrollView页面设置的是stateHiden,软键盘也不会再次展示。所以stateAlwaysHiden的作用还要继续探究。

============================================

以上是state***系列的几个属性,主要作用是控制软键盘的展示逻辑的。

从现在开始adjust***系列属性,主要是用来设置软键盘和页面UI元素之间的显示关系。

12、adjustUnspecified

It is unspecified whether the activity's main window resizes to make room for the soft keyboard, or whether the contents of the window pan to make the current focus visible on-screen. The system will automatically select one of these modes depending on whether the content of the window has any layout views that can scroll their contents. If there is such a view, the window will be resized, on the assumption that scrolling can make all of the window's contents visible within a smaller area.
This is the default setting for the behavior of the main window.
默认行为,由系统自行决定隐藏还是展示。默认行为下,ScrollView布局和非ScrollView布局展示软键盘的区别在于:软键盘弹出时,ScrollView只会滚动其中的内容。而非ScrollView会滚动整个页面,包括ActionBar。

13、adjustResize

The activity's main window is always resized to make room for the soft keyboard on screen.

Activity总是调整屏幕的大小以适应软键盘。非ScrollView布局会出现Window为了显示软键盘强行调整Activity主窗口大小的情况,UI和交互会变得比较诡异。ScrollView布局只会滚动其中的内容,不包括ActionBar等。

14、adjustPan

The activity's main window is not resized to make room for the soft keyboard. Rather, the contents of the window are automatically panned so that the current focus is never obscured by the keyboard and users can always see what they are typing. This is generally less desirable than resizing, because the user may need to close the soft keyboard to get at and interact with obscured parts of the window.

adjustPan采取了和adjustResize的思路,adjustPan不再调整主窗口的大小,而是通过移动内容来保证软键盘在可见范围内。经过试验使用adjustPan时,不论是不是ScrollView布局,都是整体向上滚动。

15、adjustNothing

由于默认的是adjustUnspecific,所以总会对UI产生影响,如果不想让UI随着软键盘的弹出有任何变动,可使用adjustNothing。

比如可以在代码中动态的调整是否响应adjust操作,如下:

 int orientation = UtilHelper.getRealScreenOrientation(this);
if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
Log.e("David", "横屏了----------");
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING);
} else if (orientation == Configuration.ORIENTATION_PORTRAIT) {
Log.e("David", "----------竖屏了");
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
}

总结:

感觉不指定adjust属性或者使用adjustUnspecified时,ScrollView布局采用adjustResize,非ScrollView布局采用adjustPan。adjustPan在两种布局下行为至少是一致的,adjustResize在非ScrollView布局下,行为是不可预测的。所以,在不确定的情况下,推荐使用默认adjust属性。