У меня есть активность с двумя EditText
s. Я вызываю requestFocus
во втором поле EditText
, поскольку по умолчанию фокус переходит к первому. Фокус, как представляется, находится во втором поле (второй получает выделенную границу), но если мы попытаемся ввести какие-либо символы с помощью аппаратной клавиатуры, текст появится в первом элементе управления EditText
. Любые идеи, почему это произойдет?
Фокусная проблема с несколькими EditTexts
Ответ 1
Трудно сказать, была ли это ваша проблема, но это маловероятно.
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 сохраняет дочернее представление, которое в настоящее время имеет фокус, если оно есть.
Предположим, у вас есть ViewGroup VG
, который содержит три настраиваемых вида (например, EditTexts) A
, B
и C
.
Вы добавили OnFocusChangeListener
в A
, который (возможно, не напрямую, а где-то внутри внутри) вызывает B.requestFocus()
, когда A
теряет фокус.
Теперь представьте, что A
имеет фокус, и пользователь нажимает на C
, вызывая A
и C
, чтобы получить фокус. Поскольку VG.mFocused
в настоящее время A
, вышеуказанная часть 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
. После некоторого количества вещей мы, наконец, вернемся из вызова в (1)
и, таким образом, в (3)
значение mFocused
теперь установлено на C
, перезаписав предыдущее изменение.
Итак, теперь мы оказываемся в неустойчивом состоянии. B
и C
оба считают, что они имеют фокус, VG
считает, что C
является сфокусированным ребенком.
В частности, нажатия клавиш заканчиваются на C
, и пользователю невозможно переключить фокус обратно на B
, потому что B
считает, что он уже имеет фокус и, следовательно, t делать что-либо в запросах фокуса; самое главное, он не вызывает VG.requestChildFocus
.
Следствие. Вы также не должны полагаться на результаты вызовов hasFocus()
, находясь внутри обработчика OnFocusChanged
, потому что информация о фокусе несовместима во внутреннем вызове.
Ответ 2
Я нашел решение.
Внутри 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();
}
});
}
}
});
Ответ 3
У меня возникла одна и та же проблема: у одного из моих EditText есть OnFocusListener, и когда он теряет фокус, я делаю некоторые преобразования, но если что-то пойдет не так, я снова попробую FFFocus и позволю пользователю решить проблему. Здесь, когда проблема возникает, я заканчиваю с 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 возвращает фокус, и действие фокусируется на следующем представлении. Надеюсь, это кому-то поможет.
Ответ 4
Попробуйте использовать requestFocus(); http://developer.android.com/reference/android/view/View.html#requestFocus()