【问题标题】:How to clear focus of all selectable elements in a View?如何清除视图中所有可选元素的焦点?
【发布时间】:2017-02-26 19:51:13
【问题描述】:

我的问题很简单。如何清除视图中可能具有焦点的所有元素的焦点 EditText -or- TextViewtextIsSelectable="true" 和文本在在 clearFocus 事件发生时)。

为什么要问(如果我没有得到上面的一般答复):

我有几个片段通过导航视图访问。我的主要目标在导航视图中打开抽屉片段中的元素焦点。我知道它可以为 NavigationDrawer 获取 onDrawerSlide 方法,并且实际上在我的 MainActivity 中设置了它,以便在抽屉打开时,如果我在其中一个片段中的 EditText 是打开的,我调用 hideSoftKeyboard 代码以便它关闭 SoftKeyboard。

我的代码来获取抽屉打开事件:(在 MainActivity 的 onCreate() 方法中)

DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
                this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close)
{
            //Hide SoftKeyboard on Navigation Drawer Open
            @Override
            public void onDrawerSlide(View drawerView, float slideOffset) {
                //Hide SoftKeyboard if it is open
                hideSoftKeyboard();

                //And Make any view having focus loose focus
 //...
//ClearFocus for the whole view is done from here (for whichever Fragment is visible right now)

                super.onDrawerSlide(drawerView, slideOffset);
            }        
};

public void hideSoftKeyboard()    //Declared outside onCreate
{
        InputMethodManager inputMethodManager = (InputMethodManager)getSystemService(Activity.INPUT_METHOD_SERVICE);
        inputMethodManager.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
}

这里,我的 hideSoftKeyboard() 代码是通用,并且无论从 MainActivity 本身看到什么 Fragment,都可以关闭 SoftKeyboard . 同样我想清除所有 EditTexts 和 TextView 的焦点(因为复制/粘贴选项在打开时显示在抽屉中间)。

我知道我可以为每个调用 onDrawerSlide 函数的 Fragment 编写代码,并为每个元素单独清除焦点,但我想知道是否有可能提供通用解决方案,如果可以,该怎么做。

(如果可能的话,这可能会产生很多影响,并且在很多情况下可能会有所帮助)

【问题讨论】:

    标签: android focus navigation-drawer android-view


    【解决方案1】:

    好吧,我终于决定不能再等待一般性的答案了,因此决定为每个片段实现onDrawerSlide。事实证明,即使这样也有点棘手,因为您需要访问工具栏并使用当前抽屉设置抽屉,并且进行一些实验会引发 NPE! (只是我平时的运气)

    所以当这闪现给我时,我正在浏览官方的 android 开发者网站以获取任何见解。为什么不使用getCurrentFocus 来获取我的当前视图,然后使用clearFocus()!瞧,它有效。我太专注于复杂的情况,以至于忘记检查简单的部分。

    所以这是我自己的问题的答案:(在 MainActivity 的 onCreate 中)

    DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
    ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close)
    {
                @Override
                public void onDrawerSlide(View drawerView, float slideOffset) {
                    hideSoftKeyboard();
    
                    getCurrentFocus().clearFocus();  //clear focus - any view having focus
    
                    super.onDrawerSlide(drawerView, slideOffset);
    }
    

    感谢@keivan Esbati 指出了一个我没有注意到的漏洞,因为我使用了虚拟视图(在布局 xml 中使用,因此一旦加载了 Layout,第一个 EditText 就不会获得焦点)。根据 Android 开发者论坛:

    clearFocus() : 当 View 清除焦点时,框架试图给予焦点 从顶部到第一个可聚焦的视图。因此,如果这个视图是 首先从可以获取焦点的顶部开始,然后是所有与 清除焦点将被调用,之后框架将给出 关注这个观点。

    对此的一个迂回方法当然是设置一个虚拟变量,该变量在加载布局后立即调用焦点(我使用的方法)或@keivan 共享的this

    【讨论】:

      【解决方案2】:

      要从视图中清除焦点,您可以调用getCurrentFocus().clearFocus() 但请记住,这只会将焦点从当前视图移动到视图中的第一个元素,而不是完全从视图中移除焦点;因此,如果布局中的第一个元素是 EditText,它将再次获得焦点。

      确保视图不再获得焦点的一种方法是将此属性添加到 xml 中的根视图中,从而使根视图能够捕获焦点:

      android:focusableInTouchMode="true"
      android:descendantFocusability="beforeDescendants"
      

      所以如果你像下面这样声明你的根元素,它会在到达子视图之前自动捕获焦点:

      <?xml version="1.0" encoding="utf-8"?>
      <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          android:focusableInTouchMode="true"
          android:descendantFocusability="beforeDescendants">
      
          <!-- Rest of Layout -->
          <.../>
      
      </LinearLayout>
      

      【讨论】:

      • 哦,那是我不知道的事情。我使用虚拟视图来关注它,而不是在打开布局后立即编辑文本。所以这就是为什么我没有注意到我猜。感谢您的告知。
      • 也会更新我的答案,以便更清楚地了解clearfocus 函数:D
      【解决方案3】:

      如果您有多个活动,并且在这些活动中只有一个活动,则您有导航视图。在这种情况下,如果您想清除对 navView 的关注,请使用此代码,

      @Override
      protected void onResume() {
          super.onResume();
      
          int size = navigationView.getMenu().size();
          for (int i = 0; i < size; i++) {
              navigationView.getMenu().getItem(i).setChecked(false);
          }
      
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-01-20
        • 2016-06-12
        • 1970-01-01
        • 2013-10-02
        • 2015-11-30
        • 1970-01-01
        • 2012-12-26
        • 2013-07-29
        相关资源
        最近更新 更多