您好,登錄后才能下訂單哦!
在項目開發中,用到編輯框的地方經常涉及到要監聽或者控制軟鍵盤的顯示/隱藏狀態。本以為這是很容易解決的一個小問題,沒想到當初碰到這個問題才明白還得花點小心思才能整好。現將針對軟鍵盤的顯示/隱藏狀態的監聽/監控方法做一些總結,以備后用。
一、點擊空白處隱藏軟鍵盤
這是具有編輯框焦點的頁面對輸入法軟鍵盤狀態監聽的一般需求和解決方法.
首先獲得InputMethodManager:
InputMethodManager manager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
監聽點擊:
/** * 點擊監聽 */ @Override public boolean onTouchEvent(MotionEvent event) { onHideSoftInput(event); return super.onTouchEvent(event); } /** * 點擊空白處,關閉輸入法軟鍵盤 */ public void onHideSoftInput(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { if (getCurrentFocus() != null && getCurrentFocus().getWindowToken() != null) { manager.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS); } } }
二、popwindow與輸入法軟鍵盤的結合
先說下自己想實現的效果:點擊頂部按鈕,打開編輯菜單popwindow并自動彈出軟鍵盤;再次點擊頂部按鈕,或者點擊編輯菜單popwindow上面的底部按鈕,關閉菜單并隱藏軟鍵盤;菜單打開狀態,點擊返回鍵,若菜單已顯示先關閉軟鍵盤,再點擊則關閉菜單。
大致效果圖如下:
1.重寫根布局,監聽根布局高度變化
對于這個需求,簡單的用上面第一點的方法是無效的。這里沒法直接通過getCurrentFocus()方法判斷頁面是否獲取焦點來控制,需要通過對popwindow的高度變化進行判斷。同時也試過下面的方法,同樣無效。
InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE); boolean isOpen=imm.isActive();//isOpen若返回true,則表示輸入法打開
popwindow的根布局我這里用的是RelativeLayout,RelativeLayout類可以通過重寫onSizeChanged方法來監聽布局大小變化。重寫一個RelativeLayout類便實現了對popwindow的高度變化的監聽了。
代碼如下:
/** * 監聽輸入法軟鍵盤顯示狀態的自定義RelativeLayout * * @author zeng * */ public class ResizeRelativeLayout extends RelativeLayout { public ResizeRelativeLayout(Context context, AttributeSet attrs) { super(context, attrs); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); if (mListener != null) { mListener.OnResizeRelative(w, h, oldw, oldh); } } // 監聽接口 private OnResizeRelativeListener mListener; public interface OnResizeRelativeListener { void OnResizeRelative(int w, int h, int oldw, int oldh); } public void setOnResizeRelativeListener(OnResizeRelativeListener l) { mListener = l; } }
2.配置布局文件,初始化UI等,代碼如下:
初始化UI代碼:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initUI(); } private void initUI() { mBtn_open = findViewById(R.id.button1); mBtn_open.setOnClickListener(this); // 編輯窗口 LayoutInflater inflater = getLayoutInflater(); View menuLayout = inflater.inflate(R.layout.menu_window, null); mEditMenuWindow = new PopupWindow(menuLayout, LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT, true); mEditMenuWindow.setBackgroundDrawable(getResources().getDrawable(R.color.white)); mEditMenuWindow.setTouchable(true); mEditMenuWindow.setFocusable(true); mEditMenuWindow.setAnimationStyle(R.style.MenuAnimation); mEditMenuWindow.setOutsideTouchable(false); mEditMenuWindow.update(); //監聽菜單消失 mEditMenuWindow.setOnDismissListener(this); // 菜單控件 mEt_menu = (EditText) menuLayout.findViewById(R.id.menu_edit); TextView btn_send = (TextView) menuLayout.findViewById(R.id.menu_send); btn_send.setOnClickListener(this); // 監聽主布局大小變化,監控輸入法軟鍵盤狀態 listenerKeyBoardState(menuLayout); }
其中menu_window.xml文件代碼如下:
<?xml version="1.0" encoding="utf-8"?> <com.example.d_popwindow_inputkeyboard.ResizeRelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/menu_layout" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" android:padding="8dp" > <EditText android:id="@+id/menu_edit" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_above="@+id/menu_send" android:layout_marginBottom="8dp" android:background="#ffffffff" android:enabled="true" android:focusable="true" android:focusableInTouchMode="true" android:gravity="top|left" android:inputType="none" android:padding="8dp" android:textSize="18sp" > <requestFocus /> </EditText> <TextView android:id="@+id/menu_send" android:layout_width="fill_parent" android:layout_height="60dp" android:layout_alignParentBottom="true" android:layout_gravity="center" android:background="#ff0f0f0f" android:gravity="center" android:text="發送" android:textColor="#ffFF6004" android:textSize="20sp" android:textStyle="bold" /> </com.example.d_popwindow_inputkeyboard.ResizeRelativeLayout>
3.打開或關閉編輯窗口,同時自動顯示或隱藏輸入法軟鍵盤。
此方法兩者的控制順序:先顯示軟鍵盤,再打開編輯窗口;先關閉編輯窗口,若軟鍵盤當前已顯示則再隱藏軟鍵盤。代碼如下:
//點擊頂部發送按鈕,打開/關閉編輯窗口 private void clickTopSend() { if (mEditMenuWindow.isShowing()) { //先關閉窗口再隱藏軟鍵盤 mEditMenuWindow.dismiss(); // 隱藏輸入法軟鍵盤 // hideKeyBoard(); } else { // 窗口顯示前顯示輸入法軟鍵盤 showKeyBoard(); // 顯示輸入窗口 mEditMenuWindow.showAsDropDown(mBtn_open, 0, 0); } } // 窗口顯示前顯示輸入法軟鍵盤 private void showKeyBoard() { InputMethodManager inputMgr = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); inputMgr.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);// 調用此方法才能自動打開輸入法軟鍵盤 mEditMenuWindow.setSoftInputMode( WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); mEditMenuWindow.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED); // 在顯示popupwindow之后調用,否則輸入法會在窗口底層 } // 隱藏輸入法軟鍵盤 private void hideKeyBoard() { InputMethodManager inputMgr = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); inputMgr.toggleSoftInput(InputMethodManager.HIDE_NOT_ALWAYS, 0);// 輸入法軟鍵盤打開時關閉,關閉時打開 mEditMenuWindow.setSoftInputMode( WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); mEditMenuWindow.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED); // 在顯示popupwindow之后調用,否則輸入法會在窗口底層 //此方法無效 // if(this.getCurrentFocus().getWindowToken() != null) // { // ((InputMethodManager) getSystemService(INPUT_METHOD_SERVICE)).hideSoftInputFromWindow(this.getCurrentFocus().getWindowToken(), // InputMethodManager.HIDE_NOT_ALWAYS);// 關閉輸入法軟鍵盤 // } } //點擊底部發送按鈕,關閉編輯窗口 private void closeButtomSend() { mEditMenuWindow.dismiss(); } //編輯窗口關閉時,隱藏輸入法軟鍵盤 @Override public void onDismiss() { // 如果軟鍵盤打開,隱藏輸入法軟鍵盤 if(mIsKeyboardOpened) { hideKeyBoard(); } }
4.判斷軟鍵盤的顯示/隱藏狀態。
通過對編輯窗口的根布局高度變化來判斷軟鍵盤是否處于顯示狀態,在接口方法OnResizeRelative(int w, int h, int oldw, int oldh)里實現對高度變化的判斷。這里主要判斷以下幾種高度變化場景:
(1)布局的當前高度小于上一次的高度,即h < oldh,因為布局被軟鍵盤頂上去了,高度變小了。這種場景同樣適用于點擊按鈕第一次打開窗口時的場景,雖然點擊按鈕時,肉眼看到的是窗口一下就充滿了大半個屏幕,也就是當前h > oldh(oldh = 0)。但事實上是,第一次打開窗口時,窗口菜單首先是充滿整個屏幕然后再根據軟鍵盤高度自動縮進的。以下是點擊【打開/發送】按鈕后,根布局的高度變化日志:
可以看出,首次打開時,窗口高度先是1038,然后自動縮進成544,并非一打開便已計算好填充高度。
(2)還有一種特殊情況,就是三星輸入法在軟鍵盤初次打開時,輸入字符后軟鍵盤高度會產生變化,同時造成根布局高度變小;若再清除已輸入的字符,此時軟鍵盤高度變小,根布局高度變大。而這兩種情況下,也就是h < oldh 或者 h > oldh時,軟鍵盤都是處于顯示狀態。
針對這種情況,我的解決方法是記錄下初次打開時根布局的初始高度值,由于h < oldh時在第(1)步已經進行了判斷了,所以這里只要判斷 h > oldh時的情況。而無論 h > oldh變化多大,只要h不超過初始高度值(且初始高度值不為0),那么便可認為當前軟鍵盤仍是處于打開狀態。
此方法運行后的日志如下:
兩種狀況下,軟鍵盤都是顯示狀態。
以下是監聽高度變化判斷的代碼:
/** * 監聽主布局大小變化,監控輸入法軟鍵盤狀態 * @param menuLayout */ private void listenerKeyBoardState(View menuLayout) { ResizeRelativeLayout mMenuLayout = (ResizeRelativeLayout) menuLayout.findViewById(R.id.menu_layout); mMenuLayout.setOnResizeRelativeListener(new ResizeRelativeLayout.OnResizeRelativeListener() { @Override public void OnResizeRelative(int w, int h, int oldw, int oldh) { mIsKeyboardOpened = false; Log.e("菜單高度", "h = " + h + ",oldh = " + oldh); //記錄第一次打開輸入法時的布局高度 if (h < oldh && oldh > 0 && mMenuOpenedHeight == 0) { mMenuOpenedHeight = h; } // 布局的高度小于之前的高度 if (h < oldh ) { mIsKeyboardOpened = true; } //或者輸入法打開情況下, 輸入字符后再清除(三星輸入法軟鍵盤在輸入后,軟鍵盤高度增加一行,清除輸入后,高度變小,但是軟鍵盤仍是打開狀態) else if((h <= mMenuOpenedHeight) && (mMenuOpenedHeight != 0)) { mIsKeyboardOpened = true; } Log.e("是否打開", "軟鍵盤 = " + mIsKeyboardOpened); } }); }
最后附上DEMO源碼,詳見附件。
三、InputMethodManager的一些相關方法(未有效使用過,僅作筆記)
1.調用顯示系統默認的輸入法
方法一、
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); imm.showSoftInput(m_receiverView,InputMethodManager.SHOW_FORCED);
m_receiverView(接受軟鍵盤輸入的視圖(View)
InputMethodManager.SHOW_FORCED(提供當前操作的標記,SHOW_FORCED表示強制顯示)
方法二、
InputMethodManager m=(InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE); m.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS);
這個InputMethodManager類里面的toggleSoftInput方法的API中的解釋是:
This method toggles the input method window display. If the input window is already displayed, it gets hidden. If not the input window will be displayed.
這個方法在界面上切換輸入法的功能,如果輸入法出于現實狀態,就將他隱藏,如果處于隱藏狀態,就顯示輸入法。
2.調用隱藏系統默認的輸入法
((InputMethodManager)getSystemService(INPUT_METHOD_SERVICE)).hideSoftInputFromWindow(WidgetSearchActivity.this.getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
(WidgetSearchActivity是當前的Activity)
3.獲取輸入法打開的狀態
InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE); boolean isOpen=imm.isActive();
isOpen若返回true,則表示輸入法打開
四、SoftInputMode輸入法軟鍵盤模式相關說明
輸入法軟鍵盤模式選項:
public int softInputMode;
以下與輸入法模式有關的各選項說明:
軟輸入區域是否可見。
public static final int SOFT_INPUT_MASK_STATE = 0x0f;
未指定狀態。
public static final int SOFT_INPUT_STATE_UNSPECIFIED = 0;
不要修改軟輸入法區域的狀態。
public static final int SOFT_INPUT_STATE_UNCHANGED = 1;
隱藏輸入法區域(當用戶進入窗口時)。
public static final int SOFT_INPUT_STATE_HIDDEN = 2;
當窗口獲得焦點時,隱藏輸入法區域。
public static final int SOFT_INPUT_STATE_ALWAYS_HIDDEN = 3;
顯示輸入法區域(當用戶進入窗口時)。
public static final int SOFT_INPUT_STATE_VISIBLE = 4;
當窗口獲得焦點時,顯示輸入法區域。
public static final int SOFT_INPUT_STATE_ALWAYS_VISIBLE = 5;
窗口應當主動調整,以適應軟輸入窗口。
public static final int SOFT_INPUT_MASK_ADJUST = 0xf0;
未指定狀態,系統將根據窗口內容嘗試選擇一個輸入法樣式。
public static final int SOFT_INPUT_ADJUST_UNSPECIFIED = 0x00;
當輸入法顯示時,允許窗口重新計算尺寸,使內容不被輸入法所覆蓋。
不可與SOFT_INPUT_ADJUSP_PAN混合使用;如果兩個都沒有設置,系統將根據窗口內容自動設置一個選項。
public static final int SOFT_INPUT_ADJUST_RESIZE = 0x10;
輸入法顯示時平移窗口。它不需要處理尺寸變化,框架能夠移動窗口以確保輸入焦點可見。
不可與SOFT_INPUT_ADJUST_RESIZE混合使用;如果兩個都沒有設置,系統將根據窗口內容自動設置一個選項。
public static final int SOFT_INPUT_ADJUST_PAN = 0x20;
當用戶轉至此窗口時,由系統自動設置,所以你不要設置它。
當窗口顯示之后該標志自動清除。
public static final int SOFT_INPUT_IS_FORWARD_NAVIGATION = 0x100;
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。