Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android 軟鍵盤的顯示與隱藏問題的研究

android 軟鍵盤的顯示與隱藏問題的研究

編輯:關於Android編程

在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窗口來處理的。
很多的時候,我們都希望能夠監聽到軟件鍵盤的顯示與關閉狀態,比如下圖的情況,

你有一個登錄界面是這樣設計的

\

你希望登錄時它是這樣的,<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4KPHA+PGltZyBzcmM9"/uploadfile/Collfiles/20140508/2014050808314879.jpg" alt="\">

然後你去嘗試給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(int w, int h,int oldw,int oldh) 方法裡監聽界面大小的變化,然後在該方法裡定義回調函數,當監聽到鍵盤被調出時,將鍵盤向上推一段距離,這樣將登錄鍵顯示出來。

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();//獲取登錄按鈕的位置信息。
                }
                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一樣。


參考文章:InputMethod


例子源碼下載地址


  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved