在做一些人性化的交互設(shè)計(jì)的時(shí)候,能夠獲取Android 鍵盤(pán)的顯示與隱藏狀態(tài)對(duì)我們有很大的幫助,但是Android 官方文檔中并沒(méi)有明確的給出 ,鍵盤(pán)顯示與隱藏的監(jiān)聽(tīng),但是我們還是可以通過(guò)計(jì)算當(dāng)前應(yīng)用的高度變化來(lái)獲取鍵盤(pán)的狀態(tài)。手機(jī)QQ對(duì)于鍵盤(pán)的處理就非常好,有著以下的幾點(diǎn)人性化設(shè)計(jì):

- 滑動(dòng)時(shí)隱藏鍵盤(pán)
- 點(diǎn)擊除鍵盤(pán)區(qū)域隱藏鍵盤(pán)
- 當(dāng)滾動(dòng)到底部時(shí)繼續(xù)拉動(dòng)彈出鍵盤(pán)
** 本文將一步一步講解實(shí)現(xiàn)上述三種設(shè)計(jì) **
1.首先獲取鍵盤(pán)顯示隱藏狀態(tài)
獲取鍵盤(pán)顯示狀態(tài)的原理是:首先利用getRootView().getHeight() 獲取屏幕高度,在利用getWindowVisibleDisplayFrame 獲取應(yīng)用顯示區(qū)域,但是這個(gè)區(qū)域不包含虛擬按鍵的區(qū)域(虛擬鍵盤(pán)、手機(jī)底部虛擬按鍵),我們根據(jù)前者與后者之差與狀態(tài)欄高度的比較來(lái)判斷鍵盤(pán)的顯示與隱藏狀態(tài)。
// 軟鍵盤(pán)的顯示狀態(tài)
private boolean ShowKeyboard;
private ViewTreeObserver.OnGlobalLayoutListener globalLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
// 應(yīng)用可以顯示的區(qū)域。此處包括應(yīng)用占用的區(qū)域,包括標(biāo)題欄不包括狀態(tài)欄
Rect r = new Rect();
layoutMain.getWindowVisibleDisplayFrame(r);
// 鍵盤(pán)最小高度
int minKeyboardHeight = 150;
// 獲取狀態(tài)欄高度
int statusBarHeight = getStatusBarHeight(mContext);
// 屏幕高度,不含虛擬按鍵的高度
int screenHeight = layoutMain.getRootView().getHeight();
// 在不顯示軟鍵盤(pán)時(shí),height等于狀態(tài)欄的高度
int height = screenHeight - (r.bottom - r.top);
if (ShowKeyboard) {
// 如果軟鍵盤(pán)是彈出的狀態(tài),并且height小于等于狀態(tài)欄高度,
// 說(shuō)明這時(shí)軟鍵盤(pán)已經(jīng)收起
if (height - statusBarHeight < minKeyboardHeight) {
ShowKeyboard = false;
Toast.makeText(mContext,"鍵盤(pán)隱藏了",Toast.LENGTH_SHORT).show();
}
} else {
// 如果軟鍵盤(pán)是收起的狀態(tài),并且height大于狀態(tài)欄高度,
// 說(shuō)明這時(shí)軟鍵盤(pán)已經(jīng)彈出
if (height - statusBarHeight > minKeyboardHeight) {
ShowKeyboard = true;
Toast.makeText(mContext,"鍵盤(pán)顯示了",Toast.LENGTH_SHORT).show();
}
}
}
};
** 需要特別指出的是,在某些手機(jī)上,比如華為mate8,底部會(huì)出現(xiàn)一個(gè)可以隨時(shí)隱藏與顯示的一行虛擬按鍵(Android雜亂生態(tài)的無(wú)奈??),所以我們要定義一個(gè)最小鍵盤(pán)高度。 **
//給最外層布局添加布局變化監(jiān)聽(tīng)
layoutMain.getViewTreeObserver().addOnGlobalLayoutListener(globalLayoutListener);
這樣根據(jù)ShowKeyboard值的變化 就能判斷鍵盤(pán)的顯示與隱藏了。
2.實(shí)現(xiàn)點(diǎn)擊其他區(qū)域隱藏鍵盤(pán)
這里利用的就是焦點(diǎn),點(diǎn)擊其他區(qū)域,鍵盤(pán)會(huì)失去焦點(diǎn),這個(gè)時(shí)候我們可以強(qiáng)制隱藏鍵盤(pán),因?yàn)镋ditText 焦點(diǎn)已經(jīng)缺失,某些隱藏鍵盤(pán)的方法可能失效。
inputText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (!hasFocus) {
InputMethodManager imm = (InputMethodManager) mContext
.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(layoutMain.getWindowToken(), 0);
}
}
});
3.實(shí)現(xiàn)滑動(dòng)隱藏鍵盤(pán),以及滑動(dòng)到底部拉出鍵盤(pán)
這里主要實(shí)現(xiàn)方法是監(jiān)聽(tīng)用戶手勢(shì),同時(shí)判斷鍵盤(pán)狀態(tài),判斷webView是否滑動(dòng)到底部了。
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
if (e1 == null || e2 == null) {
return false;
}
//判斷滑動(dòng)距離,以及速度,如果鍵盤(pán)顯示中,隱藏鍵盤(pán)。
if (Math.abs(e2.getY() - e1.getY()) > flingHeight && Math.abs(velocityY) > flingspeed) {
if (ShowKeyboard) {
closeInputMethod(mContext);
}
}
float r= mWebView.getHeight();
// WebView總高度
float webViewContentHeight = mWebView.getContentHeight()*mWebView.getScale();
// WebView的現(xiàn)高度
float webViewCurrentHeight = (mWebView.getHeight() + mWebView.getScrollY());
// 這里是判斷 鍵盤(pán)是否顯示 滑動(dòng)距離,以及是否滑動(dòng)到底部。
if (!ShowKeyboard && e1.getY() - e2.getY() > getScreenHeight(mContext) / 10 && webViewContentHeight - webViewCurrentHeight <= 10) {
popInputMethod(inputText, mContext);
}
return false;
}
注意手勢(shì)監(jiān)聽(tīng),不要遺忘以下操作:
public class MainActivity extends AppCompatActivity implements GestureDetector.OnGestureListener
mGestureDetector = new GestureDetector(mContext, this);
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
mGestureDetector.onTouchEvent(event);
return super.dispatchTouchEvent(event);
}
最后看一下實(shí)現(xiàn)的效果圖:
