Android: EditText в Dialog не подтягивает клавиатуру

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

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

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

Edit:

В соответствии с запросом, вот фрагмент кода, с которым я работаю. Я не буду беспокоиться по всему макету, но в этом конкретном приложении 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>

Код, который создает это, устанавливает видимость относительногоLayout в "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 не запускается в первую очередь, и почему это кажется таким обычным явлением!

Ответ 1

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

Кажется, что проблема (по крайней мере, в моем случае) заключается в том, что поскольку место ввода текста сначала скрыто (или вложенное или что-то еще), 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, не нужно kludges или обходных решений.

Ответ 2

У меня такая же проблема в моем приложении. Если вы разрабатываете для уровня 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...

BTW: этот фрагмент не всегда работает на эмуляторе. Я не знаю, почему.

Ответ 3

Если вы прочитаете документацию 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 в вашем случае одинаково, и он должен работать.

Ответ 4

Вышеприведенный код очень полезен. Но вы должны вызвать метод "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;
}

Ответ 5

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

    @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;
}

Ответ 6

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

    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);

Ответ 7

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

У меня есть диалог, созданный в методе onCreateDialog(), который (кажется) требует возврата dialog.show();, поэтому вы не можете добавить layoutparams в диалог, в котором создается диалог. Чтобы обойти это, просто сохраняйте метод 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);
}

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

Ответ 8

Это то, что сработало для меня. Создайте 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();.

Ответ 9

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

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;
        }
    }
}

Ответ 10

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);
}
});