Android: EditText в диалоге не запускает программную клавиатуру

82

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

Я бы предпочел, чтобы Android использовал свое собственное поведение по умолчанию для EditTexts, чем создавать мое собственное, но похоже, что все (в этих потоках) приняли, что поведение по умолчанию для EditTexts в диалогах - просто указывать курсор, а не клавиатуру. Почему это могло быть?

Для записи, ни один из этих обходных путей, похоже, у меня не работает - самое близкое, что я смог найти, - это заставить клавиатуру появляться под диалоговым окном (с помощью InputMethodManager.toggleSoftKeyboard (*)). Моя конкретная конфигурация - API15, EditText отображается в нижнем колонтитуле ListView в AlertDialog. EditText андроид: фокусируемый = «истинный» установлен, и onFocusChangeListener будет получать фокус события.

Редактировать:

По запросу, вот конкретный фрагмент кода, с которым я работаю. Я не буду беспокоиться обо всем макете, но в этом конкретном приложении EditText появляется в ответ на нажатие кнопки в диалоговом окне (аналогично представлению действий ). Он содержится в RelativeLayout, для которого по умолчанию видимость "пропала":

 <RelativeLayout 
       android:id="@+id/relLay"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:layout_centerVertical="true"
       android:visibility="gone"
       android:layout_marginTop="5dp"
       android:layout_marginBottom="5dp">

        <ImageButton
            android:id="@+id/cancelBut"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:background="@color/transparent"
            android:src="@drawable/cancelButton" 
            android:layout_margin="5dp"/>

        <ImageButton
            android:id="@+id/okBut"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_toLeftOf="@id/cancelBut"
            android:background="@color/transparent"
            android:src="@drawable/okButton"
            android:layout_margin="5dp" />

        <EditText 
            android:id="@+id/editText"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:inputType="text"
            android:focusable="true"
            android:layout_toLeftOf="@id/okBut"/>
   </RelativeLayout>

Код, который создает это, устанавливает видимость relativeLayout на «Visible» (и скрывает другие элементы пользовательского интерфейса). Этого должно быть достаточно, чтобы поднять клавиатуру, когда EditText сфокусируется, исходя из моего опыта работы с EditText. Однако по некоторым причинам это не так. Я могу установить следующее onFocusChangeListener:

    edit_text.setOnFocusChangeListener(new OnFocusChangeListener() {

            @Override
            public void onFocusChange(View v, boolean hasFocus) {
                // For whatever reason we need to request a soft keyboard.
                    InputMethodManager imm = (InputMethodManager)dlg.getWindow().getContext().getSystemService(_Context.INPUT_METHOD_SERVICE);
                    if(hasFocus)
                        imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
                    Log.v("DialogProblem", "Focus requested, " + (hasFocus?"has focus.":"doesn't have focus."));
                }
            }
        });

Используя эту конфигурацию, когда я впервые вхожу в EditText, срабатывает onFocusChangedListener и генерирует журнал, который неизменно выглядит следующим образом:

Focus requested, has focus.
Focus requested, doesn't have focus.
Focus requested, has focus.

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

Тем не менее, я хотел бы подчеркнуть, что, хотя я могу заставить этот обходной путь работать, меня в первую очередь интересует найти простую причину, по которой EditText вообще не запускается, и почему это кажется таким банальным!

Павел
источник
Не могли бы вы опубликовать соответствующий фрагмент кода (где вы устанавливаете фокус, добавляете прослушиватель фокуса и т. Д.)?
Александр Лукас,
Я могу (и сделаю это, когда вернусь к компьютеру), но я думаю, что мой более широкий вопрос не предполагает сосредоточенного слушателя. Мне интересно, почему это обычная проблема, когда редактирование текста в диалоговом окне не открывает клавиатуру. Хотя я был бы счастлив использовать клудж, если это так, но я хотел бы знать, почему это необходимо.
Пол

Ответы:

190

Итак, после большого чтения я понял, почему это проблема, и мне не нужно использовать какие-либо обходные пути.

Проблема, по-видимому, в том (по крайней мере, в моем случае), что, поскольку место, где вы вводите текст, изначально скрыто (или вложено или что-то в этом роде), AlertDialog автоматически устанавливает флаг WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM (или некоторую комбинацию этого и WindowManager .LayoutParams.FLAG_NOT_FOCUSABLE), чтобы вещи не запускали мягкий ввод для отображения.

Я нашел способ исправить это, добавив следующую строку после создания диалога:

dialog.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);

Как только это будет сделано, EditText будет действовать как обычный EditText, без каких-либо кладов или обходных путей.

Павел
источник
84
Когда я попытался сбросить флаги после создания, это не сработало. Это работало только тогда, когда я использовал его вот так: Dialog = builder.create (); Dialog.show (); Dialog.getWindow (). ClearFlags (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); Dialog.getWindow (). SetSoftInputMode (WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
Alex Fragotsis
1
@AlexanderFragotsis после того, как попробовал так много разных решений в stackoverflow, ваш комментарий - единственный, который работает! Спасибо!
Брюс
21
SOFT_INPUT_STATE_‌ VISIBLE у меня не работал. Я использовал SOFT_INPUT_STATE_ALWAYS_VISIBLE, и тогда это сработало. Просто выложи его, если у кого-то такая же проблема
kb_14
Да, я не мог заставить SOFT_INPUT_STATE_VISIBLE работать, но _ALWAYS_VISIBLE работает. кто-нибудь знает, что там происходит?
bwoogie
Очень важно сделать clearFlags()после show(), спасибо @AlexanderFragotsis
Javier Mendonça
17

У меня такая же проблема в моем приложении. Если вы разрабатываете для уровня API> = 8, вы можете использовать этот фрагмент:

dialog.setOnShowListener(new OnShowListener() {
    @Override
     public void onShow(DialogInterface dialog) {
         InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
         imm.showSoftInput(textEdit, InputMethodManager.SHOW_IMPLICIT);
    }
});

Я не нашел решения для более низких уровней API ...

Кстати: этот фрагмент не всегда работает на эмуляторе. Не знаю почему.

Джан У.
источник
2
Меня не столько интересует этот конкретный обходной путь, сколько меня интересует, почему он вообще не работает. Кроме того, я на самом деле не хочу, чтобы клавиатура отображалась в диалоговом окне, я хочу, чтобы она отображалась, когда EditText получает фокус, как поведение обычного EditText.
Пол
1
Это сработало для меня. Просто используйте AlertDialog dialog = builder.create();до и dialog.show();после вышеуказанного, если вы используете AlertDialog.Builder
Мэтт Коннолли,
1
Это единственное, что у меня сработало. Я также не думаю, что это обходной путь, это имеет смысл, когда вы читаете его с ответом ниже, цитируя документы Android о том, почему вы не можете запросить фокус, пока диалоговое окно не отобразится.
Мик Бирн
17

Если вы прочитаете документацию AlertDialog, вы найдете там:

Класс AlertDialog заботится об автоматической настройке * WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM * в зависимости от того, возвращают ли какие-либо представления в диалоговом окне значение true из View.onCheckIsTextEditor () . Обычно вы хотите, чтобы этот набор был установлен для диалогового окна без текстовых редакторов, чтобы он располагался поверх пользовательского интерфейса текущего метода ввода. Вы можете изменить это поведение, установив флаг в желаемый режим после вызова onCreate .

У меня была проблема, о которой вы упомянули, с EditText в ListView внутри диалога. Я исправил это, перезаписав пользовательский класс представления (в моем случае ListView) моим собственным FocusableListView, с перезаписью только одного метода:

public class FocusableListView extends ListView {

    public FocusableListView(Context context) {
        super(context);
    }

    public FocusableListView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public FocusableListView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    public boolean onCheckIsTextEditor() {
        // this is where the magic happens
        return true;
    }
}

Затем я использую его в файле макета как:

<?xml version="1.0" encoding="UTF-8"?>
<com.myexample.wiget.FocusableListView 
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:descendantFocusability="beforeDescendants"
android:layout_height="wrap_content" />

Вы можете перезаписать RelativeLayout в вашем случае таким же образом, и он должен работать.

philips77
источник
работает отлично, но Android Studio (версия 1.5.1) не отображает предварительный просмотр макета
Choletski
9

Это то, что у меня сработало. Создайте AlertDialog.Builder, установите заголовок, positiveButton, negativeButton. После сделайте это:

    AlertDialog dialog = builder.create();
    dialog.getWindow().clearFlags( WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
    dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
    dialog.show();
    editText.requestFocus();

Вам не нужно использовать builder.show();.

Андре Луис Рейс
источник
Спасибо, Андре, ты мужчина. Я попробовал так много решений здесь, на SO. Это единственный работающий
productioncoder
8

Приведенный выше код очень полезен. Но вы должны вызвать метод «show» после метода «create» (я не знаю почему, но только это работает в моем диалоге с EditText в ListView). В методе onCreateDialog:

@Override
protected Dialog onCreateDialog(int id) {
  switch (id) {
    case YOUR_DIALOG_ID: {
        //...
        AlertDialog a = new AlertDialog.Builder(this)./*
        ... set the properties here
        */
        .create();
        a.show(); //!!! this is very important to call the "show" method
        a.getWindow().clearFlags(
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
        return a;
    }
  //...
  }
  return null;
}
iLya2IK
источник
Этот код действительно работает? a инициализируется как AlertDialog, но конструктор является строителем. У построителей есть метод create, который возвращает диалог, у диалогов есть метод show для их отображения.
Пол
@ Пол Извините. Код был действительно неправильным в части создания диалога строителем. Я поправил.
iLya2IK
7

Спасибо! У меня есть встроенный TextEdit в последней строке ListView, встроенный в фрагмент диалогового окна предупреждения. Я использовал ваше решение по очистке флагов как сообщение для запуска, и теперь оно отлично работает.

    @Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
    builder.setTitle("My Title");
    m_adapter = new MyAdapter(getContext());
    builder.setAdapter(m_adapter, new OnClickListener() {

        @Override
        public void onClick(DialogInterface dialog, int which) {
            // TODO Auto-generated method stub

        }
    }); 

    final AlertDialog dialog = builder.create();
    final ListView listView = dialog.getListView();
    listView.setOnItemClickListener(new OnItemClickListener() {

        @Override
        public void onItemClick(AdapterView<?> parent, View view,
                int position, long id) {

        }
    });

    listView.post(new Runnable() {

        @Override
        public void run() {
            dialog.getWindow().clearFlags(
                    WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
                    WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);              
        }
    });
    return dialog;
}
farid_z
источник
4

Вот один из способов сделать это:

    final Window dialogWindow = dialog.getWindow();
    dialogWindow.clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
    dialogWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
разработчик Android
источник
2

Я хотел бы добавить к ответу Пола и комментарию Александра .

У меня есть диалог, созданный в onCreateDialog()методе, который (кажется) требует возврата dialog.show();, поэтому вы не можете добавить параметры макета в диалог, в котором создается диалог. Чтобы обойти это, просто оставьте свой onCreateDialog()метод таким же и добавьте onResume()метод следующим образом:

@Override
public void onResume() {
    super.onResume();
    Dialog dialog = getDialog();
    dialog.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
    dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
}

Это должно помочь, к счастью, у меня это работает. Довольно долго занимались этим делом.

Timmiej93
источник
0

полный код для отображения клавиатуры в диалоге:

public void onFocusChange(View v, boolean hasFocus) {
    Log.v("onFocusChange", hasFocus + " " + showkeyboard);
    if (hasFocus) {
        if (showkeyboard++ == 0) {
            alertDialog.getWindow().clearFlags(
                    WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                    | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
            alertDialog.getWindow().setSoftInputMode(
                    WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
        } else {
            showkeyboard = 1;
        }
    }
}
ангелы
источник
1
пытаюсь объяснить свой ответ. Не помещайте только код. Дайте конкретный ответ и пояснение по соответствующему коду ...
Сандип Армал Патил
0
This worked for me ----
editText.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
//dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
//dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
//dialog.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
InputMethodManager mgr = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
mgr.showSoftInput(v, InputMethodManager.SHOW_FORCED);
editText.setFocusable(true);
}
});
Маниш Саин
источник
0

просто добавьте ниже codeLine:

// для автоматического отображения клавиатуры, когда editText находится в диалоге dialog.getWindow (). setSoftInputMode (WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);

Мосаеб Масуми
источник