Bootstrap

[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是的参数设置是非对称的。

;