关于EditText屏蔽焦点的问题,及为什么clearFocus()方法失效了?

简介: 我们有时候的需求时,EditText 在不需要的时候,无法点击,或者取消它的默认焦点。

我们有时候的需求时,EditText 在不需要的时候,无法点击,或者取消它的默认焦点。

我们先看看通用解决方法。

setFousable() //设置该视图是否可以接收焦点

setFocusableInTouchMode(); //设置该视图在触摸模式下是否可以接收焦点

这里借鉴大佬的解释。

类似非触屏手机时代,需要使用键盘的上下左右去选中某个应用,然后点击确定执行。而触屏手机,我们只需要对应用点击一次,即可,无需焦点。也就是会所焦点是为了标记你目前选中的位置的。而这个在日历中却是有用的。 android:focusable与android:focusableInTouchMode 前者针对在键盘下操作的情况,如果设置为true,则键盘上下左右选中,焦点会随之移动。 而后者,显然是针对触屏情况下的,也就是我们点击屏幕的上的某个控件时,不要立即执行相应的点击逻辑,而是先显示焦点(即控件被选中),再点击才执行逻辑。

android:focusable=“true”不会改变android:focusableInTouchMode,因此只在键盘状态下显示焦点,在TouchMode状态下,依旧无法显示焦点。

android:focusable=“false”,一定会使android:focusableInTouchMode=“false”。

相对的 android:focusableInTouchMode=“false”,不会影响android:focusable。

android:focusableInTouchMode=”true”,一定会是android:focusable=“true”

 

直接上解决方法

代码:
editText.setFocusable(false)
editText.setFocusableInTouchMode(false);
xml  
android:focusable="false"
android:focusableInTouchMode="false"

按照上面的解决方案,我现在有5个 EditText,很多人会写出下面的例子:

EditText e1;
...
private void setFoucus(Boolean foucus){
    e1.setFoucusable(fouces)
    e1.setFocusableInTouchMode(focus)
    e2.setFoucusable(fouces)
    e2.setFocusableInTouchMode(focus)
    ...
    e5.setFoucusable(fouces)
    e5.setFocusableInTouchMode(focus)
}
简化版
用List来保存对象,然后for遍历,但是你的EditText,需要声明多少个呢

如果我现在有十几个输入框呢?难不成每一个都这样操作?


方法肯定有的,现在我们用另一个办法,从源头解决问题:


先上一波方法的解释


XML
android:descendantFocusability="blocksDescendants"

beforeDescendants:viewgroup会优先其子类控件而获取到焦点

afterDescendants:viewgroup只有当其子类控件不需要获取焦点时才获取焦点

blocksDescendants:viewgroup会覆盖子类控件而直接获得焦点

代码处
visable.setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);


问题定义:比如我们有EditText,由一个switch控制,当switch关闭时,editText可以输入,有焦点,否则无法点击,无焦点。


将这些输入框放在同一个线性布局里,然后利用 setDescendantFocusability() 方法,设置子类控件与viewgroup之间的焦点关系。  

 private LinearLayout layout;   //父布局实例
 ...
 private Boolean fouces=false;    //默认switch状态为false
 aSwitch.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (fouces) {
                    layout.setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
                    fouces=false;
                } else {
                    layout.clearFocus();  //清除fouces
                    layout.setDescendantFocusability(FOCUS_BLOCK_DESCENDANTS);
                    fouces=true;
                }
            }
        });

看到这,肯定很多人都觉得,这有啥难度啊,哼。我们先看运行结果。

20190303140518206.gif


咦,clearFocus()方法失效了?为什么焦点还在呢?


不着急,我们从源码角度这次来分析一波,简单粗暴。


我们先看一下clearFocus的实现

  @Override
    public void clearFocus() {
        if (DBG) {
            System.out.println(this + " clearFocus()");
        }
        if (mFocused == null) {
            super.clearFocus();
        } else {
            View focused = mFocused;
            mFocused = null;
            focused.clearFocus();
        }
    }

不管这些,我们顺着最后的调用方法走 focused.clearFocus();

 public void clearFocus() {
        if (DBG) {
            System.out.println(this + " clearFocus()");
        }
        final boolean refocus = sAlwaysAssignFocus || !isInTouchMode();
        clearFocusInternal(null, true, refocus);
    }

这里的意思是,如果焦点可用,或者非触控模式下,焦点会尝试将焦点放在第一个可以对焦的视图上,也就是说,相当于它被重置了,所以产生了我们上面图片里的问题,焦点没有被清除。


接着继续顺着代码走 clearFocusInternal(null, true, refocus);

     void clearFocusInternal(View focused, boolean propagate, boolean refocus) {
        if ((mPrivateFlags & PFLAG_FOCUSED) != 0) {
            mPrivateFlags &= ~PFLAG_FOCUSED;
            clearParentsWantFocus();
            if (propagate && mParent != null) {
                mParent.clearChildFocus(this);
            }
            onFocusChanged(false, 0, null);
            refreshDrawableState();
            if (propagate && (!refocus || !rootViewRequestFocus())) {
                notifyGlobalFocusCleared(this);
            }
        }
    }

这里清除视图中的焦点,如果propagate为true,可选地将更改向上传播到父层次结构,并放置新的焦点。


 总结一下,也就是我们需要在父布局处添加 触控模式为true,即就是android:focusableInTouchMode="true",这样当清除焦点的时候,就会将焦点赋给父布局,而不是重置到第一个EditText.到了现在,我们可以尝试一下,如果设置第一个输入框focusableInTouchMode为false,那么当你点击了别的输入框,然后点击switch,会发现,焦点会在第二个输入框,而不会在第一个。

目录
相关文章
|
2月前
按钮和手势无效问题及解决方案
按钮和手势无效问题及解决方案
21 0
按钮和手势无效问题及解决方案
|
11月前
|
Android开发
Android中保存当前按钮的状态 按back键返回之后再次进入没有改变
Android中保存当前按钮的状态 按back键返回之后再次进入没有改变
54 0
|
Android开发
android 自定义登陆对话框基类封装,且随着软键盘的弹起自动移动位置
android 自定义登陆对话框基类封装,且随着软键盘的弹起自动移动位置
|
API 开发工具 Android开发
Android 13 返回导航大变更:返回键彻底废弃 + 可预见型返回手势(1)
Android 13 返回导航大变更:返回键彻底废弃 + 可预见型返回手势(1)
Android 13 返回导航大变更:返回键彻底废弃 + 可预见型返回手势(1)
|
Shell API 开发工具
Android 13 返回导航大变更:返回键彻底废弃 + 可预见型返回手势(2)
Android 13 返回导航大变更:返回键彻底废弃 + 可预见型返回手势(2)
Android 13 返回导航大变更:返回键彻底废弃 + 可预见型返回手势(2)
|
Android开发
android如何调用显示和隐藏系统默认的输入法
android如何调用显示和隐藏系统默认的输入法
209 0
|
Android开发
在Android开发中如何移除EditText上的输入焦点
  当我们创建一个带EditText 或 AutoCompleteTextView的视图时,在加载视图时总是会把输入的焦点自动移动到第一个输入框。如下图所示:   下面是mail.xml布局文件: 1.
1281 0
|
Android开发
Android屏蔽隐藏系统自带输入键盘
Android屏蔽隐藏系统自带输入键盘 若是Activity,在AndroidMainfest.xml配置Activity属性:android:windowSoftInputMode="stateAlwaysHidden|...
1394 0