web-dev-qa-db-fra.com

Android: EditText in Dialog n'ouvre pas le clavier logiciel

J'ai donc ce qui semble être un problème commun, à savoir que le texte EditText de ma boîte de dialogue ne s'affiche pas lorsqu'il est activé. J'ai vu plusieurs solutions de contournement, comme dans ce fil , celui-ci et celui-ci (et bien d'autres), mais je n'ai jamais vu d'explication satisfaisante pour pourquoi cela se passe en premier lieu. 

Je préférerais de beaucoup qu'Android utilise son propre comportement par défaut pour EditTexts que pour construire le mien, mais il semble que tout le monde (dans ces discussions) a accepté que le comportement par défaut pour EditTexts dans les boîtes de dialogue consiste à donner simplement un curseur et pas de clavier. Pourquoi cela serait-il?

Pour mémoire, aucune de ces solutions de contournement ne semble fonctionner pour moi - le plus proche que j'ai pu arriver consiste à forcer un clavier à apparaître en dessous la boîte de dialogue (en utilisant InputMethodManager.toggleSoftKeyboard (*)). Ma configuration particulière est API15, l'EditText apparaît dans un pied de page d'un ListView dans un AlertDialog. EditText Android: focusable = "true" est défini et onFocusChangeListener est réception d'événements de focus.

Modifier:

Comme demandé, voici l'extrait de code spécifique avec lequel je travaille. Je ne m'embarrasserai pas de la mise en page complète, mais dans cette application spécifique, EditText apparaît en réponse à la pression d'un bouton de la boîte de dialogue (similaire à une vue d'action ). Il est contenu dans un RelativeLayout qui, par défaut, a la visibilité "disparue":

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

Le code qui le construit définit la visibilité de relativeLayout sur "Visible" (et masque les autres éléments de l'interface utilisateur). Cette devrait suffira à ouvrir le clavier lorsque le texte EditText sera ciblé, en fonction de mon expérience avec EditText. Cependant, pour une raison quelconque, ce n'est pas le cas. Je peux définir ce qui suit 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."));
                }
            }
        });

Avec cette configuration, lorsque je (premier} _ entre l'EditText, le déclencheur onFocusChangedListener génère un journal ressemblant invariablement à ceci:

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

Le clavier apparaît, puis disparaît, probablement parce que je le bascule deux fois, mais même si je veille à ce qu'il reste en place, c'est derrière la fenêtre de dialogue (dans une zone grisée), et il n'y a aucun moyen d'obtenir à cela sans fermer le dialogue.

Cela dit, je tiens à souligner que même si je suis capable de résoudre ce problème, je suis principalement intéressé en trouvant une raison simple pourquoi l'EditText ne déclenche pas en premier lieu, et pourquoi cela semble être si banal!

72
Paul

OK, alors après avoir beaucoup lu, j’ai compris pourquoi c’est un problème, et j’ai besoin de {pas} _ pour résoudre ce problème.

Le problème semble être (du moins dans mon cas) que, puisque l'emplacement où vous saisissez le texte est initialement masqué (ou imbriqué ou quelque chose du genre), AlertDialog définit automatiquement l'indicateur WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM (ou une combinaison de ces éléments et de WindowManager). .LayoutParams.FLAG_NOT_FOCUSABLE) afin que rien n’entraîne l’affichage d’une entrée logicielle.

La solution que j'ai trouvée pour résoudre ce problème consiste à ajouter la ligne suivante après la création de la boîte de dialogue:

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

Une fois que cela est fait, le EditText agit comme un EditText normal, aucun kludges ou solutions de contournement nécessaires.

159
Paul

J'ai le même problème dans ma propre application. Si vous développez pour un niveau d'API> = 8, vous pouvez utiliser cet extrait:

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

Je n'ai pas trouvé de solution pour les niveaux inférieurs d'API ...

BTW: Cet extrait ne fonctionne pas toujours sur l'émulateur. Je ne sais pas pourquoi.

17
Gian U.

Si vous lisez la documentation AlertDialog, vous y trouverez:

La classe AlertDialog se charge de la définition automatique de * WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM * selon que les vues de la boîte de dialogue renvoient la valeur true depuis View.onCheckIsTextEditor () . En règle générale, vous souhaitez que cet ensemble soit associé à un Dialog sans éditeur de texte, de sorte qu'il soit placé au-dessus de l'interface utilisateur de la méthode de saisie actuelle. Vous pouvez modifier ce comportement en forçant l'indicateur sur le mode souhaité après avoir appelé onCreate

J'ai eu le problème que vous avez mentionné avec EditText dans ListView dans un dialogue. Je l'ai corrigé en remplaçant la classe d'affichage personnalisée (dans mon cas, ListView) par mon propre FocusableListView, avec une seule méthode remplacée:

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

Ensuite, je l'utilise dans le fichier de mise en page comme:

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

Vous pouvez écraser le RelativeLayout dans votre cas de la même manière et cela devrait fonctionner.

13
philips77

Je vous remercie! J'ai un TextEdit intégré dans la dernière ligne de ListView incorporé dans le fragment de dialogue d'alerte. J'ai utilisé votre solution consistant à effacer les drapeaux en tant que publication exécutable et maintenant cela fonctionne parfaitement.

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

Le code ci-dessus est très utile. Mais vous devez appeler la méthode "show" après la méthode "create" (je ne sais pas pourquoi, mais cela ne fonctionne que dans mon dialogue avec EditText dans ListView) . Dans la méthode 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;
}
7
iLya2IK

C'est ce qui a fonctionné pour moi. Créez AlertDialog.Builder, définissez le titre, positifButton, négatifButton. Après cela: 

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

Vous n'avez pas besoin d'utiliser builder.show();.

5
André Luiz Reis

Voici une façon de le faire:

    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);
3
android developer

Je voudrais ajouter quelque chose à la réponse de Paul et au commentaire de Alexander .

J'ai moi-même une boîte de dialogue créée dans la méthode onCreateDialog(), qui (semble) nécessiter le renvoi de dialog.show();; vous ne pouvez donc pas ajouter de mise en page à la boîte de dialogue dans laquelle la boîte de dialogue est créée. Pour contourner ce problème, conservez votre méthode onCreateDialog() identique et ajoutez une méthode onResume() comme suit:

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

Cela devrait faire l'affaire, cela fonctionne pour moi, heureusement. Je suis dans cette affaire depuis assez longtemps.

1
Timmiej93

code complet pour afficher le clavier dans la boîte de dialogue: 

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;
        }
    }
}
0
angelsmiling
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
Manish Sain