Когда появляется мягкая клавиатура, это делает поле EditText потерянным фокусом

У меня есть несколько полей EditText в ListView. Когда я нажимаю на одно из полей EditText, клавиатура скользит в представлении (как следует), но поле EditText, которое я использовал, теряет фокус. Я попытался использовать различные методы InputMethodManager, чтобы клавиатура начала работать (чтобы обойти проблему, а не действительно ее решить), но это не сработало - клавиатура не была видна при появлении Activity.

Тип EditText number, и когда клавиатура сдвигается, это цифровая клавиатура, но когда она заканчивается сползанием, а EditText теряет фокус, она изменяется на алфавитную клавиатуру (что усиливает идею о том, что EditText больше не имеет фокуса).

Мои вопросы таковы:

1) Как я могу сделать выбор из моего поля EditText и последующее скольжение в мягкой клавиатуре, чтобы мой EditText не потерял фокус?

... в противном случае...

2) Как я могу заставить клавиатуру начать работать, поэтому ей никогда не нужно скользить (таким образом, избегая поведения, которое я считаю настолько нежелательным)?

Мой манифест включает android:windowSoftInputMode="stateAlwaysVisible", но клавиатура не появляется, пока я не коснусь EditText. Это игнорирование атрибута "stateAlwaysVisible", по-видимому, происходит только в эмуляторе - на моем подготовленном устройстве, это имеет честь, так что вопрос номер 2 выше работает на устройстве... но не в эмуляторе.

Спасибо за любую помощь, которую вы можете предоставить!

Ответ 1

Вот как я это сделал. onFocusChangeListener() вызывается несколько раз, когда вы касаетесь EditText, чтобы напечатать текст. Последовательность:

  • Если фокус был на другом представлении, тогда это представление теряет фокус
  • Целевой показатель фокусировки
  • Появится мягкая клавиатура.
  • Это заставляет цель терять фокус.
  • Код обнаруживает эту ситуацию и вызывает target.requestFocus()
  • Самый левый, самый верхний вид получает фокус, из-за ерунды Android.
  • Самый левый вид теряет фокус из-за того, что requestFocus называется
  • Целевая цель получает фокус

    //////////////////////////////////////////////////////////////////
    private final int minDelta = 300;           // threshold in ms
    private long focusTime = 0;                 // time of last touch
    private View focusTarget = null;
    
    View.OnFocusChangeListener onFocusChangeListener = new View.OnFocusChangeListener() {
        @Override
        public void onFocusChange(View view, boolean hasFocus) {
            long t = System.currentTimeMillis();
            long delta = t - focusTime;
            if (hasFocus) {     // gained focus
                if (delta > minDelta) {
                    focusTime = t;
                    focusTarget = view;
                }
            }
            else {              // lost focus
                if (delta <= minDelta  &&  view == focusTarget) {
                    focusTarget.post(new Runnable() {   // reset focus to target
                        public void run() {
                            focusTarget.requestFocus();
                        }
                    });
                }
            }
        }
    };
    

Код выше хорошо работает для всплывающих окон клавиатуры. Однако он не обнаруживает всплывающее окно "речь-текст".

Ответ 2

Вам нужно изменить свой AndroidManifest.xml

Добавьте android: windowSoftInputMode = "adjustPan" в действие, содержащее listview. Это решит вашу проблему.

    <activity android:name=".MyEditTextInListView"
              android:label="@string/app_name"
              android:windowSoftInputMode="adjustPan">

Привет

Ответ 3

В моем случае это происходит потому, что когда ListView изменяет размер, он повторно создает все элементы списка (т.е. снова вызывает getView() для каждого элемента видимого списка).

Поскольку EditText находится в макете, который я возвращаю из getView(), это означает, что это другой экземпляр EditText, чем тот, который ранее имел фокус. Второе следствие заключается в том, что когда мягкая клавиатура появляется или исчезает, я обнаружил, что теряю содержимое EditText.

Потому что я хотел, чтобы мое представление оставалось полностью доступным (т.е. я хочу, чтобы оно было изменено, а не скрыто за окном клавиатуры, а некоторые части были недоступны), я не мог использовать ответ Фрэнка, который в противном случае кажется лучшим.

Я решил это, используя OnFocusChangeListener в EditText, чтобы записать временную метку, когда фокус был утерян, а затем в getView() при воссоздании элемента списка, если текущее время находится в пределах некоторого порога, когда фокус был потерян, вызовите requestFocus(), чтобы вернуть его в EditText, о котором идет речь.

Вы также можете захватить текст из предыдущего экземпляра EditText в этой точке и перенести его в новый экземпляр.

private class MyAdapter<Type> extends ArrayAdapter<String>
    implements OnFocusChangeListener
{
    private EditText mText;
    private long mTextLostFocusTimestamp;
    private LayoutInflater mLayoutInflater;

    public MyAdapter(Context context, int resource, int textResourceId, ArrayList<String> data, LayoutInflater li) {
        super(context, resource, textResourceId, data);
        mLayoutInflater = li;
        mTextLostFocusTimestamp = -1;
    }

    private void reclaimFocus(View v, long timestamp) {
        if (timestamp == -1)
            return;
        if ((System.currentTimeMillis() - timestamp) < 250)
            v.requestFocus();
    }

    @Override public View getView (int position, View convertView, ViewGroup parent)
    {
        View v = mLayoutInflater.inflate(R.layout.mylayout, parent, false);

        EditText newText = (EditText) v.findViewById(R.id.email);
        if (mText != null)
            newText.setText(mText.getText());
        mText = newText;
        mText.setOnFocusChangeListener(this);
        reclaimFocus(mText, mTextLostFocusTimestamp);

        return v;
    }

    @Override public void onFocusChange(View v, boolean hasFocus) {
        if ((v == mText) && !hasFocus)
            mTextLostFocusTimestamp = System.currentTimeMillis();
    }
}

Ответ 4

Вы должны проверить этот код на устройстве, всегда имеющем аппаратную клавиатуру. Здесь также может произойти такое поведение.

Чтобы избежать этого, вы можете всегда видеть клавиатуру.. но это не так просто, как вы можете видеть по этой теме:

https://groups.google.com/forum/#!topic/android-developers/FyENeEdmYC0

Теоретически вам, возможно, придется создать свою собственную клавиатуру Android (хотя и использовать в качестве базы Android-клавиатуру), как описано здесь: Android: Как сделать клавиатуру всегда видимой?

Ответ 5

В AndroidManifest.xml используйте adjustNothing в активности, содержащей представления

<activity
            android:name=".ActivityName"
            android:windowSoftInputMode="adjustNothing">

Ответ 6

Если editText внутри listView просто убедитесь, что вы раздули View в методе getView этим способом.


        if (convertView == null)
        convertView = LayoutInflater.from(context).inflate(R.layout.yourItemListLayout,
                parent, false);   

Редактировать: эта работа для некоторых мобильных телефонов не все, я использую ответ от мистера Франка выше.

Ответ 7

У этого парня была такая же проблема и более того. Он решил это, используя ScrollView и LinearLayout вместо ListView.

Ответ 8

Добавить android: windowSoftInputMode = "adjustResize" в действии, содержащем listview или EditText. Это решит вашу проблему.

<activity android:name=".MainActivity"
        android:windowSoftInputMode="adjustResize">
</activity>

Ответ 9

Для тех, кто приходит сюда с Xamarin или Xamarin.Forms:

У меня была такая же проблема, но только с Android 5.x - все новые версии, включая 8.1, работали хорошо.

Очевидно, Шелтон был прав, сказав:

В моем случае это происходит потому, что при изменении размера ListView он заново создает все элементы списка (то есть снова вызывает getView() для каждого видимого элемента списка).

Мой просмотр списка также windowSoftInputMode="adjustPan" и нет, решение Фрэнка установить windowSoftInputMode="adjustPan" было для меня вариантом, потому что это означает, что клавиатура частично перемещает представление списка за пределы экрана.

Все, что мне нужно было сделать после нескольких часов отладки фокуса, - это установить стратегию кэширования ячеек в Xamarin Forms ListView:

От

CachingStrategy="RecycleElement"

к

CachingStrategy="RetainElement"

Это остановит клетки от воссоздания. Однако это может привести к снижению производительности и большому потреблению памяти для огромных списков. Быть в курсе

Ответ 10

В моем случае я вызывал root_scrollview.fullScroll(View.FOCUS_DOWN) в моем корневом ScrollView при появлении клавиатуры. Я заменил его

login_scrollview.post(new Runnable() { 
    @Override
    public void run() {
        root_scrollview.scrollTo(0,root_container.bottom)
    }
});

где root_container является непосредственным потомком root_scrollview. Это решило проблему для меня.

Примечание. Непосредственный вызов root_scrollview.scrollTo(0,root_container.bottom) не работал.