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

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

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

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

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

10 ответов


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

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


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


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

на AlertDialog класс заботится об автоматической настройке * WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM* для вас, исходя из того, каких взглядов в диалоговом возвращать true из вид.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 в вашем случае таким же образом, и это должен работать.


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

спасибо! У меня есть встроенный 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;
}

это то, что работал для меня. Создать AlertDialog.Строитель, установить название, 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();.


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

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

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

у меня самого есть диалог, который создан в 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);
}

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


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

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

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