我有两个EditText
s 的活动。我requestFocus
在第二个EditText
字段上调用,因为默认情况下焦点转到第一个字段。焦点似乎在第二个字段中(第二个获得突出显示的边框),但如果我们尝试使用硬件键盘输入任何字符,文本会出现在第一个EditText
控件中。任何想法为什么会发生?
4 回答
很难判断这是否是您的问题,但这并非不可能。
TL;DR:永远不要像requestFocus()
在onFocusChanged()
通话中那样调用改变焦点的方法。
问题在于ViewGroup.requestChildFocus()
,其中包含:
// We had a previous notion of who had focus. Clear it.
if (mFocused != child) {
if (mFocused != null) {
mFocused.unFocus();
}
mFocused = child;
}
在私有字段中mFocused
,ViewGroup 存储当前具有焦点的子视图(如果有)。
假设您有一个VG
包含三个可聚焦视图(例如 EditTexts)A
、B
和的 ViewGroup C
。
当失去焦点时,您已经添加了一个OnFocusChangeListener
(A
可能不是直接的,而是嵌套在内部的某个地方)调用。B.requestFocus()
A
现在想象一下,A
有焦点,用户点击C
,导致A
失去焦点和C
获得焦点。因为VG.mFocused
is current A
, then 的上述部分VG.requestChildFocus(C, C)
转换为:
if (A != C) {
if (A != null) {
A.unFocus(); // <-- (1)
}
mFocused = C; // <-- (3)
}
A.unFocus()
在这里做了两件重要的事情:
它标志着
A
不再有焦点。它调用您的焦点更改侦听器。
在那个监听器中,您现在调用B.requestFocus()
. 这会导致B
被标记为具有焦点,然后调用VG.requestChildFocus(B, B)
. 因为我们仍然在我用 标记的调用的深处(1)
,所以值mFocused
仍然是A
,因此这个内部调用看起来像这样:
if (A != B) {
if (A != null) {
A.unFocus();
}
mFocused = B; // <-- (2)
}
这一次,对的调用A.unFocus()
没有做任何事情,因为A
已经被标记为未聚焦(否则我们将在这里进行无限递归)。此外,没有任何事情发生标记C
为未聚焦,这是当前实际具有焦点的视图。
现在来了(2)
,它设置mFocused
为B
。经过更多的工作,我们终于从 at 的调用中返回(1)
,因此 at(3)
的值mFocused
现在设置为C
,覆盖了之前的更改。
所以现在我们最终得到了一个不一致的状态。B
并且C
都认为他们有焦点,VG
认为C
是专注的孩子。
特别是,按键以 结束C
,用户不可能将焦点切换回B
,因为B
认为它已经拥有焦点,因此不会对焦点请求执行任何操作;最重要的是,它不调用VG.requestChildFocus
.
推论:您也不应该在处理程序内部依赖调用的结果hasFocus()
,OnFocusChanged
因为在该调用内部焦点信息是不一致的。
我找到了解决方案。
在 onFocusChange 内部不要直接调用 requestFocus,而是发布一个 runnable 来请求焦点。例如在我的代码下面,
editText.setOnFocusChangeListener(new OnFocusChangeListener() {
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus == false) {
editText.post(new Runnable() {
@Override
public void run() {
editText.requestFocus();
}
});
}
}
});
我遇到了同样的问题,我的一个 EditText 有一个 OnFocusListener,当它失去焦点时,我会进行一些转换,但如果出现问题,我会再次尝试 requestFocus 并让用户解决问题。这是问题出现的时候,我最终以 EditText 为焦点,我尝试用焦点搜索视图,但 findFocus() 返回 null。我找到的唯一解决方案是创建一个 EditText 变量
private EditText requestFocus;
如果有任何问题,我将我的 EditText 设置为该变量,这是我不喜欢的但它有效,我将 OnFocusListener 设置为我活动的其他视图。当他们获得焦点时,我会这样做
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus)
if(requestFocus != null){
v.clearFocus();
requestFocus.requestFocus();
requestFocus = null;
}
}
我从拥有它的视图中清除焦点,我请求 Focus 并将变量 requestFocus 设置为 null。
我相信这种情况正在发生,因为在我请求焦点时,还没有人拥有焦点,我的 EditText 重新获得焦点,并且活动将焦点转移到下一个视图。希望它对某人有所帮助。
尝试使用 requestFocus(); http://developer.android.com/reference/android/view/View.html#requestFocus ()