溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Android項目:輸入法軟鍵盤顯示/隱藏的監(jiān)聽和控制,InputMethodManager用法研究

發(fā)布時間:2020-06-24 15:58:40 來源:網(wǎng)絡(luò) 閱讀:25188 作者:glblong 欄目:移動開發(fā)

    在項目開發(fā)中,用到編輯框的地方經(jīng)常涉及到要監(jiān)聽或者控制軟鍵盤的顯示/隱藏狀態(tài)。本以為這是很容易解決的一個小問題,沒想到當(dāng)初碰到這個問題才明白還得花點小心思才能整好?,F(xiàn)將針對軟鍵盤的顯示/隱藏狀態(tài)的監(jiān)聽/監(jiān)控方法做一些總結(jié),以備后用。


一、點擊空白處隱藏軟鍵盤

這是具有編輯框焦點的頁面對輸入法軟鍵盤狀態(tài)監(jiān)聽的一般需求和解決方法.

首先獲得InputMethodManager:

       InputMethodManager manager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);


監(jiān)聽點擊:

    /**
     * 點擊監(jiān)聽
     */
    @Override
    public boolean onTouchEvent(MotionEvent event)
    {
        onHideSoftInput(event);
        return super.onTouchEvent(event);
    }
    
    /**
     * 點擊空白處,關(guān)閉輸入法軟鍵盤
     */
    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與輸入法軟鍵盤的結(jié)合

    先說下自己想實現(xiàn)的效果:點擊頂部按鈕,打開編輯菜單popwindow并自動彈出軟鍵盤;再次點擊頂部按鈕,或者點擊編輯菜單popwindow上面的底部按鈕,關(guān)閉菜單并隱藏軟鍵盤;菜單打開狀態(tài),點擊返回鍵,若菜單已顯示先關(guān)閉軟鍵盤,再點擊則關(guān)閉菜單。

    大致效果圖如下:

Android項目:輸入法軟鍵盤顯示/隱藏的監(jiān)聽和控制,InputMethodManager用法研究




1.重寫根布局,監(jiān)聽根布局高度變化

對于這個需求,簡單的用上面第一點的方法是無效的。這里沒法直接通過getCurrentFocus()方法判斷頁面是否獲取焦點來控制,需要通過對popwindow的高度變化進(jìn)行判斷。同時也試過下面的方法,同樣無效。


InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
boolean isOpen=imm.isActive();//isOpen若返回true,則表示輸入法打開


    popwindow的根布局我這里用的是RelativeLayout,RelativeLayout類可以通過重寫onSizeChanged方法來監(jiān)聽布局大小變化。重寫一個RelativeLayout類便實現(xiàn)了對popwindow的高度變化的監(jiān)聽了。

代碼如下:

/**
 * 監(jiān)聽輸入法軟鍵盤顯示狀態(tài)的自定義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);
        }
    }
    
    // 監(jiān)聽接口
    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();
        //監(jiān)聽菜單消失
        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);
        
        
        // 監(jiān)聽主布局大小變化,監(jiān)控輸入法軟鍵盤狀態(tài)
        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="發(fā)送"
        android:textColor="#ffFF6004"
        android:textSize="20sp"
        android:textStyle="bold" />


</com.example.d_popwindow_inputkeyboard.ResizeRelativeLayout>



3.打開或關(guān)閉編輯窗口,同時自動顯示或隱藏輸入法軟鍵盤。

  此方法兩者的控制順序:先顯示軟鍵盤,再打開編輯窗口;先關(guān)閉編輯窗口,若軟鍵盤當(dāng)前已顯示則再隱藏軟鍵盤。代碼如下:

    //點擊頂部發(fā)送按鈕,打開/關(guān)閉編輯窗口
    private void clickTopSend()
    {
        if (mEditMenuWindow.isShowing())
        {
            //先關(guān)閉窗口再隱藏軟鍵盤
            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);// 調(diào)用此方法才能自動打開輸入法軟鍵盤
        mEditMenuWindow.setSoftInputMode(
                WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
        mEditMenuWindow.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED); // 在顯示popupwindow之后調(diào)用,否則輸入法會在窗口底層
    }
    
    // 隱藏輸入法軟鍵盤
    private void hideKeyBoard()
    {
        InputMethodManager inputMgr = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
        inputMgr.toggleSoftInput(InputMethodManager.HIDE_NOT_ALWAYS, 0);// 輸入法軟鍵盤打開時關(guān)閉,關(guān)閉時打開
        mEditMenuWindow.setSoftInputMode(
                WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
        mEditMenuWindow.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED); // 在顯示popupwindow之后調(diào)用,否則輸入法會在窗口底層

        //此方法無效
        //        if(this.getCurrentFocus().getWindowToken() != null)
//        {
//            ((InputMethodManager) getSystemService(INPUT_METHOD_SERVICE)).hideSoftInputFromWindow(this.getCurrentFocus().getWindowToken(),
//                    InputMethodManager.HIDE_NOT_ALWAYS);// 關(guān)閉輸入法軟鍵盤
//        }
        
    }

    
    //點擊底部發(fā)送按鈕,關(guān)閉編輯窗口
    private void closeButtomSend()
    {
        mEditMenuWindow.dismiss();        
    }

    //編輯窗口關(guān)閉時,隱藏輸入法軟鍵盤
    @Override
    public void onDismiss()
    {
        // 如果軟鍵盤打開,隱藏輸入法軟鍵盤
        if(mIsKeyboardOpened)
        {
            hideKeyBoard();
        }
    }



4.判斷軟鍵盤的顯示/隱藏狀態(tài)。

  通過對編輯窗口的根布局高度變化來判斷軟鍵盤是否處于顯示狀態(tài),在接口方法OnResizeRelative(int w, int h, int oldw, int oldh)里實現(xiàn)對高度變化的判斷。這里主要判斷以下幾種高度變化場景:


(1)布局的當(dāng)前高度小于上一次的高度,即h < oldh,因為布局被軟鍵盤頂上去了,高度變小了。這種場景同樣適用于點擊按鈕第一次打開窗口時的場景,雖然點擊按鈕時,肉眼看到的是窗口一下就充滿了大半個屏幕,也就是當(dāng)前h > oldh(oldh = 0)。但事實上是,第一次打開窗口時,窗口菜單首先是充滿整個屏幕然后再根據(jù)軟鍵盤高度自動縮進(jìn)的。以下是點擊【打開/發(fā)送】按鈕后,根布局的高度變化日志:

Android項目:輸入法軟鍵盤顯示/隱藏的監(jiān)聽和控制,InputMethodManager用法研究

可以看出,首次打開時,窗口高度先是1038,然后自動縮進(jìn)成544,并非一打開便已計算好填充高度。


(2)還有一種特殊情況,就是三星輸入法在軟鍵盤初次打開時,輸入字符后軟鍵盤高度會產(chǎn)生變化,同時造成根布局高度變小;若再清除已輸入的字符,此時軟鍵盤高度變小,根布局高度變大。而這兩種情況下,也就是h < oldh 或者 h > oldh時,軟鍵盤都是處于顯示狀態(tài)。

Android項目:輸入法軟鍵盤顯示/隱藏的監(jiān)聽和控制,InputMethodManager用法研究


針對這種情況,我的解決方法是記錄下初次打開時根布局的初始高度值,由于h < oldh時在第(1)步已經(jīng)進(jìn)行了判斷了,所以這里只要判斷 h > oldh時的情況。而無論 h > oldh變化多大,只要h不超過初始高度值(且初始高度值不為0),那么便可認(rèn)為當(dāng)前軟鍵盤仍是處于打開狀態(tài)。


此方法運行后的日志如下:

Android項目:輸入法軟鍵盤顯示/隱藏的監(jiān)聽和控制,InputMethodManager用法研究

兩種狀況下,軟鍵盤都是顯示狀態(tài)。


以下是監(jiān)聽高度變化判斷的代碼:

    /**
     * 監(jiān)聽主布局大小變化,監(jiān)控輸入法軟鍵盤狀態(tài)
     * @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;
                }
                //或者輸入法打開情況下, 輸入字符后再清除(三星輸入法軟鍵盤在輸入后,軟鍵盤高度增加一行,清除輸入后,高度變小,但是軟鍵盤仍是打開狀態(tài))
                else if((h <= mMenuOpenedHeight) && (mMenuOpenedHeight != 0))
                {
                    mIsKeyboardOpened = true;
                }

                Log.e("是否打開", "軟鍵盤  = " + mIsKeyboardOpened);
            }
        });
    }


最后附上DEMO源碼,詳見附件。




三、InputMethodManager的一些相關(guān)方法(未有效使用過,僅作筆記)

1.調(diào)用顯示系統(tǒng)默認(rèn)的輸入法

方法一、

InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);

imm.showSoftInput(m_receiverView,InputMethodManager.SHOW_FORCED);

m_receiverView(接受軟鍵盤輸入的視圖(View)

InputMethodManager.SHOW_FORCED(提供當(dāng)前操作的標(biāo)記,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.

這個方法在界面上切換輸入法的功能,如果輸入法出于現(xiàn)實狀態(tài),就將他隱藏,如果處于隱藏狀態(tài),就顯示輸入法。


2.調(diào)用隱藏系統(tǒng)默認(rèn)的輸入法

((InputMethodManager)getSystemService(INPUT_METHOD_SERVICE)).hideSoftInputFromWindow(WidgetSearchActivity.this.getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);

(WidgetSearchActivity是當(dāng)前的Activity)


3.獲取輸入法打開的狀態(tài)

InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
boolean isOpen=imm.isActive();

isOpen若返回true,則表示輸入法打開



四、SoftInputMode輸入法軟鍵盤模式相關(guān)說明


輸入法軟鍵盤模式選項:

public int softInputMode;


以下與輸入法模式有關(guān)的各選項說明:


軟輸入?yún)^(qū)域是否可見。

public static final int SOFT_INPUT_MASK_STATE = 0x0f;



未指定狀態(tài)。

public static final int SOFT_INPUT_STATE_UNSPECIFIED = 0;


不要修改軟輸入法區(qū)域的狀態(tài)。

public static final int SOFT_INPUT_STATE_UNCHANGED = 1;


隱藏輸入法區(qū)域(當(dāng)用戶進(jìn)入窗口時)。

public static final int SOFT_INPUT_STATE_HIDDEN = 2;


當(dāng)窗口獲得焦點時,隱藏輸入法區(qū)域。

public static final int SOFT_INPUT_STATE_ALWAYS_HIDDEN = 3;


顯示輸入法區(qū)域(當(dāng)用戶進(jìn)入窗口時)。

public static final int SOFT_INPUT_STATE_VISIBLE = 4;


當(dāng)窗口獲得焦點時,顯示輸入法區(qū)域。

public static final int SOFT_INPUT_STATE_ALWAYS_VISIBLE = 5;


窗口應(yīng)當(dāng)主動調(diào)整,以適應(yīng)軟輸入窗口。

public static final int SOFT_INPUT_MASK_ADJUST = 0xf0;


未指定狀態(tài),系統(tǒng)將根據(jù)窗口內(nèi)容嘗試選擇一個輸入法樣式。

public static final int SOFT_INPUT_ADJUST_UNSPECIFIED = 0x00;


當(dāng)輸入法顯示時,允許窗口重新計算尺寸,使內(nèi)容不被輸入法所覆蓋。

不可與SOFT_INPUT_ADJUSP_PAN混合使用;如果兩個都沒有設(shè)置,系統(tǒng)將根據(jù)窗口內(nèi)容自動設(shè)置一個選項。

public static final int SOFT_INPUT_ADJUST_RESIZE = 0x10;


輸入法顯示時平移窗口。它不需要處理尺寸變化,框架能夠移動窗口以確保輸入焦點可見。

不可與SOFT_INPUT_ADJUST_RESIZE混合使用;如果兩個都沒有設(shè)置,系統(tǒng)將根據(jù)窗口內(nèi)容自動設(shè)置一個選項。

public static final int SOFT_INPUT_ADJUST_PAN = 0x20;


當(dāng)用戶轉(zhuǎn)至此窗口時,由系統(tǒng)自動設(shè)置,所以你不要設(shè)置它。

當(dāng)窗口顯示之后該標(biāo)志自動清除。

public static final int SOFT_INPUT_IS_FORWARD_NAVIGATION = 0x100;




















向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI