Android: EditText in Dialog nie wyświetla miękkiej klawiatury

82

Mam więc coś, co wydaje się być częstym problemem, a mianowicie tym, że tekst edycji w moim oknie dialogowym nie pojawia się, gdy jest aktywny. Widziałem kilka obejść, takich jak w tym wątku , tym i tym (i wielu innych), ale nigdy nie widziałem satysfakcjonującego wyjaśnienia, dlaczego tak się dzieje.

Wolałbym, aby Android używał własnego domyślnego zachowania dla EditTexts, niż budował własne, ale wydaje się, że wszyscy (w tych wątkach) zaakceptowali, że domyślnym zachowaniem dla EditTexts w oknach dialogowych jest po prostu podanie kursora bez klawiatury. Dlaczego miałoby to być?

Tak na marginesie, żadne z tych obejść nie wydaje się działać dla mnie - najbliższe, jakie udało mi się osiągnąć, to wymuszenie pojawienia się klawiatury pod oknem dialogowym (za pomocą InputMethodManager.toggleSoftKeyboard (*)). Moja konkretna konfiguracja to API15, EditText pojawia się w stopce w ListView w ramach AlertDialog. EditText android: aktywowana = „true” jest ustawiona, a onFocusChangeListener jest odbieranie zdarzeń ostrości.

Edytować:

Zgodnie z prośbą, oto konkretny fragment kodu, z którym pracuję. Nie będę zawracał sobie głowy całym układem, ale w tej konkretnej aplikacji EditText pojawia się w odpowiedzi na naciśnięcie przycisku w oknie dialogowym (podobnie jak w widoku akcji ). Jest zawarty w RelativeLayout, który domyślnie ma widoczność „zniknęła”:

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

Kod, który to tworzy, ustawia widoczność RelativeLayout na „Visible” (i ukrywa inne elementy UI). To powinno wystarczyć, aby podnieść klawiaturę, gdy EditText zostanie skupiony, na podstawie moich doświadczeń z EditText. Jednak z jakiegoś powodu tak nie jest. Mogę ustawić następującą wartość 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."));
                }
            }
        });

Korzystając z tej konfiguracji, kiedy po raz pierwszy wprowadzam EditText, onFocusChangedListener wyzwala i generuje dziennik, który niezmiennie wygląda następująco:

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

Klawiatura pojawia się, a następnie znika, prawdopodobnie dlatego, że przełączam ją dwa razy, ale nawet gdy upewnię się, że pozostaje podniesiona, znajduje się za oknem dialogowym (w szarym obszarze) i nie ma sposobu, aby się do niej dostać bez zamykania okna .

To powiedziawszy, chciałbym podkreślić, że chociaż mogę sprawić, że to obejście zadziała, przede wszystkim jestem zainteresowany znalezieniem prostego powodu, dla którego EditText nie jest wyzwalany w pierwszej kolejności i dlaczego to wydaje się być tak powszechne!

Paweł
źródło
Czy mógłbyś opublikować odpowiedni fragment kodu (gdzie ustawiasz fokus, dodajesz odbiornik fokusu itp.)?
Alexander Lucas
Mogę (i zrobię to, gdy wrócę do komputera), ale myślę, że moje szersze pytanie nie dotyczy skupionego słuchacza. Zastanawiam się, dlaczego wydaje się, że częstym problemem jest to, że edycja tekstu w oknie dialogowym nie powoduje otwarcia klawiatury. Chociaż chętnie użyłbym kluge, jeśli to jest sposób na zrobienie tego, ale chciałbym wiedzieć, dlaczego takie coś jest konieczne.
Paul

Odpowiedzi:

190

OK, więc po dużym przeczytaniu zorientowałem się, dlaczego jest to problem i nie potrzebuję żadnych obejść.

Wydaje się, że problem (przynajmniej w moim przypadku) polega na tym, że skoro miejsce, w którym wpisujesz tekst jest początkowo ukryte (lub zagnieżdżone lub coś w tym rodzaju), AlertDialog automatycznie ustawia flagę WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM (lub jakaś kombinacja tego i WindowManager .LayoutParams.FLAG_NOT_FOCUSABLE), aby rzeczy nie powodowały pojawienia się miękkich danych wejściowych.

Sposób, w jaki znalazłem rozwiązanie tego problemu, polega na dodaniu następującego wiersza po utworzeniu okna dialogowego:

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

Gdy to zrobisz, EditText zachowuje się jak normalny EditText, bez zbędnych zmian ani obejść.

Paweł
źródło
84
Kiedy próbowałem wyczyścić flagi po utworzeniu, nie zadziałało. Działało tylko wtedy, gdy użyłem go w ten sposób: 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 po wypróbowaniu tak wielu różnych rozwiązań na stackoverflow, Twój komentarz jest jedynym, który działa! Dziękuję Ci!
Bruce
21
SOFT_INPUT_STATE_‌ VISIBLE nie działa dla mnie. Użyłem SOFT_INPUT_STATE_ALWAYS_VISIBLE i wtedy zadziałało. Po prostu
opublikuj
Tak, nie mogłem też zmusić SOFT_INPUT_STATE_VISIBLE do pracy, ale _ALWAYS_VISIBLE działa. ktoś wie, co się tam dzieje?
bwoogie
Bardzo ważne do zrobienia clearFlags()później show(), dzięki @AlexanderFragotsis
Javier Mendonça
17

Mam ten sam problem we własnej aplikacji. Jeśli tworzysz dla poziomu API> = 8, możesz użyć tego fragmentu:

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

Nie znalazłem rozwiązania dla niższych poziomów API ...

BTW: ten fragment kodu nie zawsze działa na emulatorze. Nie wiem dlaczego.

Gian U.
źródło
2
Nie jestem tak bardzo zainteresowany tym konkretnym obejściem, ale interesuje mnie, dlaczego w ogóle nie działa. Ponadto nie chcę, aby klawiatura pojawiała się w oknie dialogowym, chcę, aby pojawiała się, gdy tekst EditText zyskuje fokus, tak jak zachowanie normalnego EditText.
Paul
1
To zadziałało dla mnie. Po prostu użyj AlertDialog dialog = builder.create();przed i dialog.show();po powyższym, jeśli używasz AlertDialog.Builder
Matt Connolly
1
To jedyny, który działał dla mnie. Nie sądzę również, że jest to obejście, ma to sens, gdy czytasz go z odpowiedzią poniżej, cytując z dokumentów Androida, dlaczego nie możesz poprosić o skupienie się, dopóki okno dialogowe nie zostanie faktycznie wyświetlone.
Mick Byrne
17

Jeśli przeczytasz dokumentację AlertDialog, znajdziesz tam:

AlertDialog klasa dba o automatyczne ustawianie * WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM * dla Ciebie na podstawie tego, czy jakieś poglądy w zamian dialogowym prawdziwymi od View.onCheckIsTextEditor () . Ogólnie rzecz biorąc, ten zestaw jest potrzebny do okna dialogowego bez edytorów tekstu, aby został umieszczony na wierzchu bieżącego interfejsu użytkownika metody wprowadzania. Możesz zmodyfikować to zachowanie, zmuszając flagę do pożądanego trybu po wywołaniu onCreate .

Miałem problem, o którym wspomniałeś z EditText w ListView w oknie dialogowym. Naprawiłem to, zastępując niestandardową klasę widoku (w moim przypadku ListView) moim własnym FocusableListView, z nadpisaniem tylko jednej metody:

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

Następnie używam go w pliku układu jako:

<?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" />

Możesz nadpisać RelativeLayout w swoim przypadku w ten sam sposób i powinno działać.

philips77
źródło
działa idealnie, ale Android Studio (wersja 1.5.1) nie wyświetla podglądu układu
Choletski
9

To właśnie zadziałało dla mnie. Utwórz AlertDialog.Builder, ustaw tytuł, pozytywnyButton, negatywnyButton. Po wykonaniu tej czynności:

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

Nie musisz używać builder.show();.

André Luiz Reis
źródło
Dzięki André, jesteś mężczyzną. Wypróbowałem tak wiele rozwiązań tutaj na SO. To jedyny, który działa
productioncoder
8

Powyższy kod jest bardzo pomocny. Ale musisz wywołać metodę "show" po metodzie "create" (nie wiem dlaczego, ale działa to tylko w moim oknie dialogowym z EditText w ListView). W metodzie 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
źródło
Czy ten kod faktycznie działa? a jest inicjowany jako AlertDialog, ale konstruktor jest konstruktorem. Twórcy mają metodę create, która zwraca okno dialogowe, okna dialogowe mają metodę show, która je pokazuje.
Paul
@Paul Przepraszam. Kod był naprawdę nieprawidłowy w części tworzenia okna dialogowego przez konstruktora. Poprawiłem to.
iLya2IK
7

Dziękuję Ci! Mam osadzony TextEdit w ostatnim wierszu ListView osadzony we fragmencie okna dialogowego alertu. Użyłem twojego rozwiązania usuwania flag jako postu, który można uruchomić i teraz działa idealnie.

    @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
źródło
4

Oto jeden sposób, aby to zrobić:

    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);
programista Androida
źródło
2

Chciałbym dodać do odpowiedzi Paula i komentarza Aleksandra .

Sam mam okno dialogowe, które zostało utworzone w onCreateDialog()metodzie, które (wydaje się) wymaga zwrócenia dialog.show();, dlatego nie możesz dodać parametrów układu do okna dialogowego, w którym zostało utworzone okno dialogowe. Aby obejść ten problem, po prostu zachowaj onCreateDialog()tę samą metodę i dodaj onResume()metodę w następujący sposób:

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

To powinno załatwić sprawę, na szczęście działa na mnie. Zajmuję się tą sprawą już od jakiegoś czasu.

Timmiej93
źródło
0

pełny kod pokazujący klawiaturę w oknie dialogowym:

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;
        }
    }
}
uśmiech aniołów
źródło
1
próbuję wyjaśnić twoją odpowiedź. Nie umieszczaj tylko kodu. Podaj konkretną odpowiedź i wyjaśnienie dotyczące odpowiedniego kodu ...
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);
}
});
Manish Sain
źródło
0

wystarczy dodać poniżej codeLine:

// aby automatycznie wyświetlać klawiaturę, gdy editText jest w oknie dialogowym dialog.getWindow (). setSoftInputMode (WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);

Mosayeb Masoumi
źródło