Android: EditText в диалоге не поднимает программную клавиатуру - PullRequest
76 голосов
/ 01 февраля 2012

Итак, у меня есть, как мне кажется, общая проблема, которая заключается в том, что 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>

Код, который создает это, устанавливает видимостьlativeLayout на «Видимый» (и скрывает другие элементы пользовательского интерфейса). Этого должно быть достаточно, чтобы поднять клавиатуру, когда 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 ]

168 голосов
/ 02 февраля 2012

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

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

17 голосов
/ 02 февраля 2012

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

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

15 голосов
/ 01 октября 2013

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

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

7 голосов
/ 02 мая 2013

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

Код выше очень полезен. Но вы должны вызывать метод "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 голосов
/ 28 июня 2017

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

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

3 голосов
/ 21 октября 2015

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

    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);
1 голос
/ 28 марта 2016

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

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

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

0 голосов
/ 25 декабря 2015
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 голосов
/ 13 сентября 2012

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

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