Android: EditText у діалоговому вікні не піднімає м'яку клавіатуру


82

Отже, у мене є, здається, загальна проблема, яка полягає в тому, що EditText у моєму діалоговому вікні не відображається, коли він фокусується. Я бачив кілька обхідних шляхів, наприклад, у цій темі , цій і цій (і багато інших), але я ніколи не бачив задовільного пояснення, чому це відбувається в першу чергу.

Я б набагато віддав перевагу, щоб андроїд використовував власну поведінку за замовчуванням для 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>

Код, який будує це, встановлює видимість relaLayout на "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 не спрацьовує в першу чергу, і чому це здається, це так буденно!


Не могли б ви опублікувати відповідний фрагмент коду (де ви встановлюєте фокус, додаєте слухач фокусу тощо)?
Олександр Лукас

Я можу (і зроблю це, коли повернусь до комп’ютера), але я думаю, що моє ширше питання не стосується уваги слухача. Мені цікаво, чому здається поширеною проблемою те, що редагування тексту у діалоговому вікні не відкриває клавіатуру. Хоча я б із задоволенням використав клудж, якщо це спосіб це зробити, але я хотів би знати, чому така річ необхідна.
Пол

Відповіді:


188

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

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


83
Коли я намагався очистити прапори після створення, це не спрацювало. Він працював лише тоді, коли я використовував його так: 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);
Алекс Фрагоціс,

1
@AlexanderFragotsis, спробувавши стільки різних рішень на stackoverflow, ваш коментар єдиний, який працює! Дякую!
Брюс

20
SOFT_INPUT_STATE_‌ VISIBLE не працював у мене. Я використовував SOFT_INPUT_STATE_ALWAYS_VISIBLE, і тоді це спрацювало. Просто
викладіть

Так, я не міг отримати 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 ...

BTW: Цей фрагмент не завжди працює на емуляторі. Не знаю чому.


2
Мене не так цікавить цей конкретний обхідний шлях, як цікавить, чому він не працює в першу чергу. Крім того, я насправді не хочу, щоб клавіатура відображалася з діалоговим вікном, я хочу, щоб вона відображалася, коли EditText набуває фокусу, як поведінка звичайного EditText.
Пол

1
Це спрацювало для мене. Просто використовуйте AlertDialog dialog = builder.create();до та dialog.show();після вищезазначеного, якщо ви використовуєте AlertDialog.Builder
Метт Конноллі

1
Це єдиний, який працював у мене. Я також не думаю, що це обхідне рішення, це має сенс, коли ви читаєте його з відповіддю нижче, цитуючи документи з Android про те, чому ви не можете запитувати фокус, доки діалогове вікно фактично не відображається.
Mick Byrne

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 у вашому випадку так само, і він повинен працювати.


працює ідеально, але Android Studio (версія 1.5.1) не відображає макет попереднього перегляду
Холецький

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. Це єдиний, який працює
виробничий

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

Чи справді працює цей код? 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;
}

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

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

Це повинно зробити трюк, це працює на мене, на щастя. Давно займався цією справою.


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
намагаючись пояснити свою відповідь. Не ставте лише код. Дайте конкретну відповідь та пояснення щодо відповідного коду ...
Sandip Armal Patil

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.