Фокус проблема с несколькими EditTexts - PullRequest
16 голосов
/ 09 июня 2010

У меня есть активность с двумя EditText с. Я вызываю requestFocus во втором EditText поле, поскольку по умолчанию фокус переходит к первому. Фокус, кажется, находится во втором поле (второе получает выделенную границу), но если мы попытаемся ввести какие-либо символы с помощью аппаратной клавиатуры, текст появится в первом элементе управления EditText. Есть идеи, почему это будет происходить?

Ответы [ 4 ]

28 голосов
/ 04 апреля 2014

Трудно сказать, была ли это ваша проблема, но это не исключено.

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 a 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() делает здесь две важные вещи:

  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), который устанавливает mFocused в B. После еще нескольких вещей мы наконец возвращаемся из вызова на (1), и, таким образом, на (3) значение mFocused теперь установлено на C, перезаписывая предыдущее изменение .

Так что теперь мы в конечном итоге в незавершенном состоянии. B и C оба думают, что у них есть фокус, VG считает C сфокусированным ребенком.

В частности, нажатия клавиш заканчиваются на C, и пользователь не может переключить фокус обратно на B, потому что B считает, что он уже имеет фокус и, следовательно, не делать что-либо на запросы фокуса; самое главное, он не звонит VG.requestChildFocus.

Следствие. Вам также не следует полагаться на результаты вызовов hasFocus(), когда они находятся внутри обработчика OnFocusChanged, поскольку во время этого вызова информация о фокусе противоречива.

5 голосов
/ 29 мая 2014

Я нашел решение.

Внутри 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();
                        }
                  });
             }
        }
    });
1 голос
/ 06 августа 2011

Я столкнулся с той же проблемой, один из моих EditText имеет OnFocusListener, и когда он теряет фокус, я делаю некоторые преобразования, но если что-то идет не так, я пытаюсь снова запросить Focus и позволить пользователю решить проблему. Вот когда проблема обнаруживается, я в конечном итоге с EditText с фокусом, я попытался найти представление с фокусом, но findFocus () вернул ноль. Единственное решение, которое я нашел, было создать переменную 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 восстанавливает фокус, и действие дает фокус следующему представлению. Надеюсь, это кому-нибудь поможет.

0 голосов
/ 31 марта 2011

Попробуйте использовать requestFocus ();http://developer.android.com/reference/android/view/View.html#requestFocus()

...