18

我有两个EditTexts 的活动。我requestFocus在第二个EditText字段上调用,因为默认情况下焦点转到第一个字段。焦点似乎在第二个字段中(第二个获得突出显示的边框),但如果我们尝试使用硬件键盘输入任何字符,文本会出现在第一个EditText控件中。任何想法为什么会发生?

4

4 回答 4

30

很难判断这是否是您的问题,但这并非不可能。

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)AB和的 ViewGroup C

当失去焦点时,您已经添加了一个OnFocusChangeListenerA可能不是直接的,而是嵌套在内部的某个地方)调用。B.requestFocus()A

现在想象一下,A有焦点,用户点击C,导致A失去焦点和C获得焦点。因为VG.mFocusedis current A, then 的上述部分VG.requestChildFocus(C, C)转换为:

if (A != C) {
    if (A != null) {
        A.unFocus();          // <-- (1)
    }

    mFocused = C;             // <-- (3)
}

A.unFocus()在这里做了两件重要的事情:

  1. 它标志着A不再有焦点。

  2. 它调用您的焦点更改侦听器。

在那个监听器中,您现在调用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),它设置mFocusedB。经过更多的工作,我们终于从 at 的调用中返回(1),因此 at(3)的值mFocused现在设置为C覆盖了之前的更改

所以现在我们最终得到了一个不一致的状态。B并且C都认为他们有焦点,VG认为C是专注的孩子。

特别是,按键以 结束C用户不可能将焦点切换回B,因为B认为它已经拥有焦点,因此不会对焦点请求执行任何操作;最重要的是,它调用VG.requestChildFocus.

推论:您也不应该在处理程序内部依赖调用的结果hasFocus()OnFocusChanged因为在该调用内部焦点信息是不一致的。

于 2014-04-04T12:26:37.060 回答
9

我找到了解决方案。

在 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();
                        }
                  });
             }
        }
    });
于 2014-05-29T16:31:57.453 回答
1

我遇到了同样的问题,我的一个 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 重新获得焦点,并且活动将焦点转移到下一个视图。希望它对某人有所帮助。

于 2011-08-06T18:54:47.907 回答
0

尝试使用 requestFocus(); http://developer.android.com/reference/android/view/View.html#requestFocus ()

于 2011-03-30T21:14:39.923 回答