如何清除视图中所有可选元素的焦点?
How to clear focus of all selectable elements in a View?
我的问题很简单。如何清除视图中可能具有焦点的所有元素的焦点(like EditText
-or- TextView
textIsSelectable="true"
并且在发生 clearFocus 事件时 选择了其中的文本)。
为什么要问(以防我没有得到对上述内容的一般答复):
我有 几个片段 正在通过 导航视图 访问。我的主要目标 是在导航视图中在抽屉打开 时失去对片段中元素的关注。我知道它有可能获得 NavigationDrawer 的 onDrawerSlide
方法,并且实际上在我的 MainActivity 中设置了它,以便在抽屉打开时,如果我在其中一个片段中的 EditText 打开,我调用 hideSoftKeyboard 代码以便它关闭软键盘。
我的代码获取抽屉打开事件:(在 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() 代码是 generic 并且 可以关闭 SoftKeyboard,无论在什么 Fragment 可见来自 MainActivity 本身的时刻。 同样我想clearFocus我所有的EditTexts和TextView(因为Copy/Paste选项在打开时显示在抽屉中间).
我知道我可以为每个 Fragment 编写代码调用 onDrawerSlide 函数并分别为每个元素清除 Focus,但我想知道是否可以使用通用解决方案,如果可以,如何实现。
(如果可能的话,这可能会有很多影响,并且在很多情况下可能会有所帮助)
好吧,我终于决定不能再等待一般答案了,因此决定为每个片段 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 因此一旦加载布局,第一个 EditText 就会执行得不到焦点)。根据 Android 开发者论坛:
clearFocus() : When a View clears focus the framework is trying to give focus
to the first focusable View from the top. Hence, if this View is the
first from the top that can take focus, then all callbacks related to
clearing focus will be invoked after which the framework will give
focus to this view.
对此的一个迂回当然是设置一个虚拟变量,一旦加载布局(我使用的方法)或 就调用焦点,如@keivan 所共享。
要从视图中清除焦点,您可以调用 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>
如果您有多个 activity 而在这些活动中只有一个 activity 您有导航视图。在这种情况下,如果您想明确关注 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);
}
}
我的问题很简单。如何清除视图中可能具有焦点的所有元素的焦点(like EditText
-or- TextView
textIsSelectable="true"
并且在发生 clearFocus 事件时 选择了其中的文本)。
为什么要问(以防我没有得到对上述内容的一般答复):
我有 几个片段 正在通过 导航视图 访问。我的主要目标 是在导航视图中在抽屉打开 时失去对片段中元素的关注。我知道它有可能获得 NavigationDrawer 的 onDrawerSlide
方法,并且实际上在我的 MainActivity 中设置了它,以便在抽屉打开时,如果我在其中一个片段中的 EditText 打开,我调用 hideSoftKeyboard 代码以便它关闭软键盘。
我的代码获取抽屉打开事件:(在 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() 代码是 generic 并且 可以关闭 SoftKeyboard,无论在什么 Fragment 可见来自 MainActivity 本身的时刻。 同样我想clearFocus我所有的EditTexts和TextView(因为Copy/Paste选项在打开时显示在抽屉中间).
我知道我可以为每个 Fragment 编写代码调用 onDrawerSlide 函数并分别为每个元素清除 Focus,但我想知道是否可以使用通用解决方案,如果可以,如何实现。
(如果可能的话,这可能会有很多影响,并且在很多情况下可能会有所帮助)
好吧,我终于决定不能再等待一般答案了,因此决定为每个片段 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 因此一旦加载布局,第一个 EditText 就会执行得不到焦点)。根据 Android 开发者论坛:
clearFocus() : When a View clears focus the framework is trying to give focus to the first focusable View from the top. Hence, if this View is the first from the top that can take focus, then all callbacks related to clearing focus will be invoked after which the framework will give focus to this view.
对此的一个迂回当然是设置一个虚拟变量,一旦加载布局(我使用的方法)或
要从视图中清除焦点,您可以调用 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>
如果您有多个 activity 而在这些活动中只有一个 activity 您有导航视图。在这种情况下,如果您想明确关注 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);
}
}