Android:windowSoftInputMethod軟鍵盤彈出的問題淺析

一、淺析


很多時候在一些需要輸入的界面上,我們需要呼出軟鍵盤來打字。Android中會在AndroidMainfest.xml文件的 < activity />節點使用
android:windowSoftInputMode=”XXX”屬性來設定呼出軟鍵盤的屬性。
下面就對一些屬性做一個簡單的列表說明。

  • “stateUnspecified” 軟鍵盤的狀態(是否它是隱藏或可見)沒有被指定。系統將選擇一個合適的狀態或依賴於主題的設置。這個是爲了軟件盤行爲默認的設置。

  • “stateUnchanged” 軟鍵盤被保持無論它上次是什麼狀態,是否可見或隱藏,當主窗口出現在前面時。

  • “stateHidden” 當用戶選擇該Activity時,軟鍵盤被隱藏——也就是,當用戶確定導航到該Activity時,而不是返回到它由於離開另一個Activity。

  • “stateVisible” 軟鍵盤是可見的,當那個是正常合適的時(當用戶導航到Activity主窗口時)。

  • “stateAlwaysVisible” 當用戶選擇這個Activity時,軟鍵盤是可見的——也就是,也就是,當用戶確定導航到該Activity時,而不是返回到它由於離開另一個Activity。

  • “adjustUnspecified” 它不被指定是否該Activity主窗口調整大小以便留出軟鍵盤的空間,或是否窗口上的內容得到屏幕上當前的焦點是可見的。系統將自動選擇這些模式中一種主要依賴於是否窗口的內容有任何佈局視圖能夠滾動他們的內容。如果有這樣的一個視圖,這個窗口將調整大小,這樣的假設可以使滾動窗口的內容在一個較小的區域中可見的。這個是主窗口默認的行爲設置。

  • “adjustResize” 該Activity主窗口總是被調整屏幕的大小以便留出軟鍵盤的空間。

  • “adjustPan” 該Activity主窗口並不調整屏幕的大小以便留出軟鍵盤的空間。相反,當前窗口的內容將自動移動以便當前焦點從不被鍵盤覆蓋和用戶能總是看到輸入內容的部分。這個通常是不期望比調整大小,因爲用戶可能關閉軟鍵盤以便獲得與被覆蓋內容的交互操作。

二、舉例


經常使用的是adjustPan和adjustResize,根據不同業務或者情景的需要也會用到像stateUnchanged(保持上次鍵盤狀態)、stateHidden(隱藏鍵盤)等屬性。

下面的例子是對adjustPan和adjustResize的一個比較。
注:adjustPan與adjustResize的最大不同就是,adjustResize會改變佈局的大小,軟鍵盤與當前Activity佈局在同一層次,會將界面擠上去。

1、adjustPan

  • XML佈局:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.david.keyborad">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name="com.example.david.keyborad.MainActivity"
            android:windowSoftInputMode="adjustPan">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

</manifest>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
    tools:context="com.example.david.keyborad.MainActivity">


    <com.example.david.keyborad.MyLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <EditText
            android:id="@+id/edittext"
            android:layout_width="150dp"
            android:layout_height="wrap_content"
            android:inputType="text"
            android:hint="Hello World!" />
    </com.example.david.keyborad.MyLayout>
</RelativeLayout>
  • 代碼
package com.example.david.keyborad;

import android.content.res.Configuration;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

public class MainActivity extends AppCompatActivity {
    private  int cout = 0;
    private static final String CONFIG_CHANGE = "Activity config count =";
    private static final String ONATTACHE_TO_WINDOW = "Activity attach count =";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        Log.e(CONFIG_CHANGE+(cout++),"onConfigruationChanged");
    }

    @Override
    public void onAttachedToWindow() {
        super.onAttachedToWindow();
        Log.e(CONFIG_CHANGE+(cout++),"onAttachToWindows()");
    }
}

------------------------------------------------------


package com.example.david.keyborad;

import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.LinearLayout;

/**
 * Created by David on 2016/3/22.
 */
public class MyLayout extends LinearLayout {
    private int onDrawCount = 0;
    private int onLayoutCount = 0;
    private int onMeasureCount = 0;
    private int onSizeChangedCout = 0;
    private static final String ON_DRAW = "invoke Drawcount = ";
    private static final String ON_MEASURE = " invoke Measure count = ";
    private static final String ON_LAYOUT = "invoke layout count = ";
    private static final String ON_SIZECHANGE = "invoked size count = ";
    public MyLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Log.e(ON_DRAW+(onDrawCount++),"onDraw() is invoked!");
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        Log.e(ON_SIZECHANGE+(onSizeChangedCout++),"onSizeChanged() is invoked! \n"+"newHight = "+h+"  newWidth = "+w+"  oldw = "+oldw+"  oldh = "+oldh );
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        Log.e(ON_MEASURE+(onMeasureCount++),"onMeasure() is invoked!\n"+"mesurewidth = "+widthMeasureSpec+"  mesureheight = "+heightMeasureSpec);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        Log.e(ON_LAYOUT+(onLayoutCount++),"onLayout() is invoked!"+" left = "+l+"  top = "+t+" right = "+r+"bottom = "+b);
    }
}

我們來看看Log日誌的輸出,這是點擊輸入框之後的Log(初始化的時候沒有複製進來):

03-22 11:23:54.668 27959-27959/com.example.david.testkeyboard E/ Measure invoke count =6: onMeasure() is invoked!
                                                                                          mesurewidth = 1073742820  mesureheight = 1073743324
03-22 11:23:54.668 27959-27959/com.example.david.testkeyboard E/ Measure invoke count =7: onMeasure() is invoked!
                                                                                          mesurewidth = 1073742820  mesureheight = 1073743324
03-22 11:23:54.668 27959-27959/com.example.david.testkeyboard E/layout invoke count =2: onLayout() is invoked! left = 42  top = 42 right = 1038bottom = 1542
03-22 11:23:54.817 27959-27959/com.example.david.testkeyboard E/ Measure invoke count =8: onMeasure() is invoked!
                                                                                          mesurewidth = 1073742820  mesureheight = 1073743324
03-22 11:23:54.817 27959-27959/com.example.david.testkeyboard E/ Measure invoke count =9: onMeasure() is invoked!
                                                                                          mesurewidth = 1073742820  mesureheight = 1073743324
03-22 11:23:54.817 27959-27959/com.example.david.testkeyboard E/layout invoke count =3: onLayout() is invoked! left = 42  top = 42 right = 1038bottom = 1542

稍微有點長,不過我們可以看到,點擊輸入框之後:
1、調用了4次onMeasure()測量Layout的大小,中間隔了一次onLayout()。
2、調用2次onLayout()方法設置Layout的方向、位置。

屏幕大小並沒有改變,鍵盤是直接覆蓋在當前Layout上面。

2、adjustResize

  • XML佈局
    (只要改動 android:windowSoftInputMode=”adjustResize”)

這是點擊輸入框之後的輸出日誌:

03-22 11:31:17.394 27599-27599/com.example.david.testkeyboard E/ invoke Measure count = 4: onMeasure() is invoked!
                                                                                           mesurewidth = 1073742820  mesureheight = 1073743324
03-22 11:31:17.394 27599-27599/com.example.david.testkeyboard E/ invoke Measure count = 5: onMeasure() is invoked!
                                                                                           mesurewidth = 1073742820  mesureheight = 1073743324
03-22 11:31:17.394 27599-27599/com.example.david.testkeyboard E/invoke layout count = 1: onLayout() is invoked! left = 42  top = 42 right = 1038bottom = 1542
03-22 11:31:17.752 27599-27599/com.example.david.testkeyboard E/ invoke Measure count = 6: onMeasure() is invoked!
                                                                                           mesurewidth = 1073742820  mesureheight = 1073743324
03-22 11:31:17.752 27599-27599/com.example.david.testkeyboard E/ invoke Measure count = 7: onMeasure() is invoked!
                                                                                           mesurewidth = 1073742820  mesureheight = 1073743324
03-22 11:31:17.752 27599-27599/com.example.david.testkeyboard E/invoke layout count = 2: onLayout() is invoked! left = 42  top = 42 right = 1038bottom = 1542
03-22 11:31:17.950 27599-27599/com.example.david.testkeyboard E/ invoke Measure count = 8: onMeasure() is invoked!
                                                                                           mesurewidth = 1073742820  mesureheight = 1073743324
03-22 11:31:17.950 27599-27599/com.example.david.testkeyboard E/ invoke Measure count = 9: onMeasure() is invoked!
                                                                                           mesurewidth = 1073742820  mesureheight = 1073743324
03-22 11:31:17.961 27599-27599/com.example.david.testkeyboard E/ invoke Measure count = 10: onMeasure() is invoked!
                                                                                            mesurewidth = 1073742820  mesureheight = 1073742549
03-22 11:31:17.961 27599-27599/com.example.david.testkeyboard E/ invoke Measure count = 11: onMeasure() is invoked!
                                                                                            mesurewidth = 1073742820  mesureheight = 1073742549
03-22 11:31:17.961 27599-27599/com.example.david.testkeyboard E/invoked size count = 1: onSizeChanged() is invoked! 
                                                                                        newHight = 725  newWidth = 996  oldw = 996  oldh = 1500
03-22 11:31:17.961 27599-27599/com.example.david.testkeyboard E/invoke layout count = 3: onLayout() is invoked! left = 42  top = 42 right = 1038bottom = 767

我們發現,Log日誌輸入與上面adjustPan大致一樣:
1、onMeasure方法調用了幾次
2、onLayout方法也調用了幾次

但是最大的不同在於,adjustResize屬性之後會調用onSizeChanged方法,說明佈局的大小發生了改變。同時我們也可以看到,newHeiht = 725,而oldHeight=1500。這個就是adjustResize與adjustPan的不同之處,具體來說大家都建議採用adjustResize屬性,這樣可以不妨礙用戶在輸入的時候瀏覽其他的內容。不過有些時候也需要adjustPan來覆蓋在當前界面上以使得用戶聚焦於輸入當前的內容。

還有其他的屬性還沒有使用過,以後使用到了再一一說明,我覺得根據需求來找自己想要的效果是最好的。

發佈了54 篇原創文章 · 獲贊 44 · 訪問量 23萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章