У меня есть активность с двумя 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()