在android中,常常會和輸入法的軟件鍵盤交互。在Manifest文件中,系統給activity的一個屬性-windowSoftInputMode來控制輸入法的顯示方式。
該屬性提供了Activity的window與軟鍵盤的window交互的方式。這里的屬性設置有雙方面的影響:
1.軟鍵盤的顯示與隱藏。-當Activity界面成為用戶的焦點時,或隱藏或顯示。
2。
對Activty的主window窗體進行調整。或者將Activity的window窗體調小以便為軟鍵盤騰出空間,或者當Activity的部分window被軟件蓋住時,移動Activity的內容以便用戶可以看到當前的焦點。
你至少要從下列屬性值選取一項對其設置,要么是”state...“,要么是”adjust...“。
你能夠設置多個值。設置不同的屬性值。要用|進行分開。
比方:
以下是對屬性的值的描寫敘述。
值
描寫敘述
”stateUnSpecified“
不指定軟件的狀態(顯示或隱藏)。系統會依據主題中的設置來選擇對應的狀態。 該屬性軟鍵盤的默認設置。
”stateUnchnaged“
總是保持上次軟鍵盤的狀態。當Activity進入到最前端時,不論是它上次它是顯示或隱藏。保持不變。
”stateHidden“
當用戶進入目標Activity時。軟鍵盤保持隱藏狀態。這里的Activity是用戶是向前進入Activity,而不是因為退出其他Activity退回到目標Activity。
”stateVisible“
僅僅有條件合適(當用戶前進進入到Activity的主window),就會顯示鍵盤
”stateAlawaysVisible“
當用戶選擇進入目標Activity時。軟鍵盤被設置為可見的。這里的Activity是用戶向前進入的Activity,而不是因為退出其他Activity而回到目標Activity
"adjustUnspecified"
不指定是否去調整Activity的界面。或者調整Activity窗體的大小以便為軟鍵盤騰出空間或者移動窗體的內容來屏幕上當前的焦點可見。系統會自己主動選擇當中一種模式,這依賴于窗體是包括能夠滑動其內容的view.如有這種視圖,窗體的大小就會被調整。在這種假定的情況下,非常小的滑動就能夠使用窗體的內容可見。
該屬性是主windowr默認設置。
”adjustResize“
Activity的窗體總是被調整其大小以便為軟鍵盤騰出空間。
”adjustPan“
Activity的主窗體不會被調整其大小以便為軟鍵盤騰出空間。相反,窗體的內容會被自己主動移動以便當前的焦點不會被軟鍵盤遮住,用戶能夠總是看到他輸入的內容。
這個值一般用于用戶非常少想調整窗體的大小的情況下。由于用戶可能須要關閉軟鍵盤來與窗體的其他部分進行交互。
從上面系統的描寫敘述了解了系統在處理兩個交互時都顯示Activity和軟鍵盤都是看作window窗體來處理的。
非常多的時候,我們都希望可以監聽到軟件鍵盤的顯示與關閉狀態。比方下圖的情況,
你有一個登錄界面是這樣設計的
你希望登錄時它是這種,
然后你去嘗試給activity的windowSoftInputMode屬性加上值,當你加上?adjustResize時。它是這種
你不甘心。你將adjustResize改動成adjustPan,結果是這種
沒有辦法。僅僅有靠我們自己來監聽鍵盤的顯示或隱藏來動態改變布局。如今的問題是怎么監聽到鍵盤的動態改變呢。系統并沒有提供對應的方法。我們能夠通過兩種方法來實現。
1.在adjustResize屬性下。activity的窗體大小會發生改變,而窗體中的layout的大小也必定后會發生改變。
當view大小發生改變時,必定會引起onSizeChanged(int, int, int, int)的回調。所以可能自己定義一個Layout。來監測onSizeChanged()函數的回調。然后在當中的作對應的處理。
這種方法也是網上傳的最多的方法。
2.借助ViewTreeOberserver類。ViewTreeOberserver能夠用來注冊一個監聽器。它能監聽view樹的全局變化。
這些變化包含但不限于,整個View的布局,繪制傳遞的源頭,觸摸模式的變化。
第一種方法的實現:
自己定義一個Layout。以RelativeLayout為例,
能夠在onSizeChanged(intw,inth,intoldw,intoldh)方法里監聽界面大小的變化,然后在該方法里定義回調函數。當監聽到鍵盤被調出時,將鍵盤向上推一段距離,這樣將登錄鍵顯示出來。
package com.example.keyboardlistener;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.RelativeLayout;
public class KeyboardLayout extends RelativeLayout {
private onSizeChangedListener mChangedListener;
private static final String TAG ="KeyboardLayoutTAG";
private boolean mShowKeyboard = false;
public KeyboardLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
}
public KeyboardLayout(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}
public KeyboardLayout(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
Log.d(TAG, "onMeasure-----------");
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// TODO Auto-generated method stub
super.onLayout(changed, l, t, r, b);
Log.d(TAG, "onLayout-------------------");
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
// TODO Auto-generated method stub
super.onSizeChanged(w, h, oldw, oldh);
Log.d(TAG, "--------------------------------------------------------------");
Log.d(TAG, "w----" + w + "\n" + "h-----" + h + "\n" + "oldW-----" + oldw + "\noldh----" + oldh);
if (null != mChangedListener && 0 != oldw && 0 != oldh) {
if (h < oldh) {
mShowKeyboard = true;
} else {
mShowKeyboard = false;
}
mChangedListener.onChanged(mShowKeyboard);
Log.d(TAG, "mShowKeyboard----- " + mShowKeyboard);
}
}
public void setOnSizeChangedListener(onSizeChangedListener listener) {
mChangedListener = listener;
}
interface onSizeChangedListener{
void onChanged(boolean showKeyboard);
}
}
在主Activity里創建一個Handler。當監聽到布局發生變化時,通過Handler更新UI。
package com.example.keyboardlistener;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.ViewTreeObserver.OnPreDrawListener;
import android.widget.Button;
import com.example.keyboardlistener.KeyboardLayout.onSizeChangedListener;
public class MainActivity extends Activity {
private static final String TAG = "KeyboardLayoutTAG";
private KeyboardLayout mRoot;
private Button mLogin;
private int mLoginBottom;
private static final int KEYBOARD_SHOW = 0X10;
private static final int KEYBOARD_HIDE = 0X20;
private boolean mGetBottom = true;
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
switch (msg.what) {
case KEYBOARD_HIDE:
mRoot.setPadding(0, 0, 0, 0);
break;
case KEYBOARD_SHOW:
int mRootBottom = mRoot.getBottom();
Log.d(TAG, "the mLoginBottom is " + mLoginBottom);
mRoot.setPadding(0, mRootBottom - mLoginBottom, 0, 0);
break;
default:
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getActionBar().hide();
mRoot = (KeyboardLayout) findViewById(R.id.root_view);
mLogin = (Button) findViewById(R.id.login);
mRoot.setOnSizeChangedListener(new onSizeChangedListener() {
@Override
public void onChanged(boolean showKeyboard) {
// TODO Auto-generated method stub
if (showKeyboard) {
mHandler.sendMessage(mHandler.obtainMessage(KEYBOARD_SHOW));
Log.d(TAG, "show keyboard");
} else {
mHandler.sendMessage(mHandler.obtainMessage(KEYBOARD_HIDE));
}
}
});
mRoot.getViewTreeObserver().addOnPreDrawListener(new OnPreDrawListener() {
@Override
public boolean onPreDraw() {
// TODO Auto-generated method stub
if (mGetBottom) {
mLoginBottom = mLogin.getBottom();//獲取登錄button的位置信息。
}
mGetBottom = false;
return true;
}
});
}
// @Override
// public boolean onCreateOptionsMenu(Menu menu) {
// // Inflate the menu; this adds items to the action bar if it is present.
// getMenuInflater().inflate(R.menu.main, menu);
// return true;
// }
}
另外一種方法的實現:
借助ViewTreeObserver類對你想監聽的view加入OnGlobalLayoutListener監聽器。然后在onGlobalLayout()方法里窗體的變化情況來推斷鍵盤是否被調出來了。以下是ViewTreeObserver監聽的部分的代碼:
mRoot.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
int offset = mRoot.getRootView().getHeight() - mRoot.getHeight();
//依據視圖的偏移值來推斷鍵盤是否顯示
if (offset > 300) {
mHandler.sendMessage(mHandler.obtainMessage(KEYBOARD_SHOW));
} else {
mHandler.sendMessage(mHandler.obtainMessage(KEYBOARD_HIDE));
}
}
});
當中Handler的詳細實現同上述結構中的Handler一樣。