天天看點

[ANDROID] EditText 自動擷取焦點(彈出軟鍵盤)的控制問題

非對稱式focus設定

EditText 在頁面啟動時一般會自動擷取焦點,就會彈出軟鍵盤。

如果不希望頁面啟動就自動彈出軟鍵盤,可以對 EditText 如下設定:

EditText.setFocusable(false);
           

果然就OK了。不會自動彈出界面了。

但這樣之後,再點選EditText就沒有反應了,無法呼出軟鍵盤。

于是,理所當然滴再對稱地反向設定一下,覺得應該就OK了吧:

EditText.setFocusable(true);
           

結果發現沒效果,點選EditText仍然無反應。神了。

難道這個API的參數是一次性的?改變後沒法再設定回去?

原來要恢複focus,這樣設定才行:

EditText.setFocusableInTouchMode(true);
           

下面簡單看下根本原因 root cause,setFocusable(false)是怎麼操作的。來看看View.java裡的原生API:

public void setFocusable(boolean focusable) {
        setFocusable(focusable ? FOCUSABLE : NOT_FOCUSABLE);
    }

    //實際調用生效在這裡
    public void setFocusable(@Focusable int focusable) {
        if ((focusable & (FOCUSABLE_AUTO | FOCUSABLE)) == 0) {
            setFlags(0, FOCUSABLE_IN_TOUCH_MODE);//這句是關鍵
        }
        setFlags(focusable, FOCUSABLE_MASK);
    }

           

代碼面前就沒有秘密了。setFocusable(false)的時候,會調用成setFocusable(NOT_FOCUSABLE),然後 if ((focusable & (FOCUSABLE_AUTO | FOCUSABLE)) == 0) 這個條件就會成立,就把FOCUSABLE_IN_TOUCH_MODE這個标志清除了。

但後來setFocusable(true),這個 if ((focusable & (FOCUSABLE_AUTO | FOCUSABLE)) == 0) 是不成立的,是以就相當于單純的一句setFlags(focusable, FOCUSABLE_MASK)。

這個說明一下,FOCUSABLE_MASK 是針對非觸屏有效的,如android電視機。FOCUSABLE_IN_TOUCH_MODE 就是針對觸屏裝置,就是手機平闆。

是以針對觸屏裝置要恢複 focus 的能力,需要用setFocusableInTouchMode(true)。看看源碼:

public void setFocusableInTouchMode(boolean focusableInTouchMode) {
        // Focusable in touch mode should always be set before the focusable flag
        // otherwise, setting the focusable flag will trigger a focusableViewAvailable()
        // which, in touch mode, will not successfully request focus on this view
        // because the focusable in touch mode flag is not set
        setFlags(focusableInTouchMode ? FOCUSABLE_IN_TOUCH_MODE : 0, FOCUSABLE_IN_TOUCH_MODE);

        // Clear FOCUSABLE_AUTO if set.
        if (focusableInTouchMode) {
            // Clears FOCUSABLE_AUTO if set.
            setFlags(FOCUSABLE, FOCUSABLE_MASK);
        }
    }
           

總結一下,

setFocusable

  • true 開啟,隻針對非觸屏有效
  • false 關閉,對所有裝置生效

setFocusableInTouchMode

  • true 開啟,對所有裝置有效
  • false 關閉,隻針對觸屏裝置

是以這兩個API是的參數設定是非對稱的。