web-dev-qa-db-fra.com

Lorsque le clavier virtuel apparaît, mon champ EditText perd le focus

J'ai quelques champs EditText dans un ListView. Lorsque je tape sur l'un des champs EditText, le clavier se glisse dans la vue (comme il se doit), mais le champ EditText que j'ai tapé perd le focus. J'ai essayé d'utiliser diverses méthodes InputMethodManager pour faire apparaître le clavier (afin de résoudre le problème plutôt que de le résoudre réellement), mais cela n'a pas fonctionné - le clavier n'était pas visible lorsque l'activité est apparue.

Le type de l’EditText est number, et lorsque le clavier est enfoncé, c’est un clavier numérique, mais quand il finit de glisser et que l’EditText perd le focus, il devient le clavier alphabétique (ce qui renforce l’idée que l’EditText n’a plus le focus). .

Mes questions sont les suivantes:

1) Comment puis-je faire la sélection de mon champ EditText et le glissement ultérieur du clavier logiciel not faire perdre le focus à mon EditText?

... à défaut ... 

2) Comment puis-je faire en sorte que le clavier se mette en place afin qu'il ne glisse jamais (évitant ainsi le comportement que je trouve si désagréable)?

Mon manifeste inclut Android:windowSoftInputMode="stateAlwaysVisible", mais le clavier n'apparaît pas tant que je n'ai pas tapé sur un EditText. Cette ignorance de l'attribut 'stateAlwaysVisible' semble ne se produire que dans l'émulateur - sur mon périphérique fourni, elle est honorée. La question 2 ci-dessus fonctionne donc sur le périphérique ... mais pas dans l'émulateur. 

Merci pour toute l'aide que vous pourrez fournir!

50
Kyle Humfeld

Voici comment je l'ai fait. La onFocusChangeListener() est appelée plusieurs fois lorsque vous touchez une EditText pour y taper du texte. La séquence est:

  1. Si le focus était sur une vue différente, cette vue perd le focus
  2. La cible gagne le focus
  3. Un clavier logiciel apparaît.
  4. Cela provoque la perte de concentration de la cible
  5. Le code détecte cette situation et appelle target.requestFocus ()
  6. La vue la plus à gauche et la plus haute gagne le focus, en raison du non-sens d'Android
  7. La vue la plus à gauche perd le focus, car requestFocus est appelé.
  8. La cible finit par se concentrer

    //////////////////////////////////////////////////////////////////
    private final int minDelta = 300;           // threshold in ms
    private long focusTime = 0;                 // time of last touch
    private View focusTarget = null;
    
    View.OnFocusChangeListener onFocusChangeListener = new View.OnFocusChangeListener() {
        @Override
        public void onFocusChange(View view, boolean hasFocus) {
            long t = System.currentTimeMillis();
            long delta = t - focusTime;
            if (hasFocus) {     // gained focus
                if (delta > minDelta) {
                    focusTime = t;
                    focusTarget = view;
                }
            }
            else {              // lost focus
                if (delta <= minDelta  &&  view == focusTarget) {
                    focusTarget.post(new Runnable() {   // reset focus to target
                        public void run() {
                            focusTarget.requestFocus();
                        }
                    });
                }
            }
        }
    };
    

Le code ci-dessus fonctionne bien pour les fenêtres contextuelles du clavier. Cependant, il ne détecte pas le pop-up parole-à-texte. 

13
SoloPilot

Vous devez changer votre AndroidManifest.xml

Ajoutez Android: windowSoftInputMode = "adjustPan" dans l'activité contenant la vue de liste . Cela résoudra votre problème.

    <activity Android:name=".MyEditTextInListView"
              Android:label="@string/app_name"
              Android:windowSoftInputMode="adjustPan">

Cordialement

118
Frank

Dans mon cas, cela se produit car lorsque ListView est redimensionné, il recrée tous les éléments de la liste (c.-à-d. Qu'il appelle à nouveau getView () pour chaque élément de la liste visible).

Étant donné que EditText se trouve dans la présentation que je retourne de getView (), cela signifie qu'il s'agit d'une instance différente de EditText par rapport à celle qui avait le focus précédemment. Une conséquence secondaire est que, lorsque le clavier logiciel apparaît ou disparaît, j'ai constaté que je perdais le contenu de EditText.

Parce que je voulais que mon point de vue reste entièrement accessible (c'est-à-dire que je souhaite le redimensionner au lieu de le cacher derrière la fenêtre du clavier avec certaines parties inaccessibles), je ne pouvais pas utiliser la réponse de Frank, qui semble par ailleurs être la meilleure approche.

J'ai résolu ce problème en utilisant un OnFocusChangeListener sur le EditText pour enregistrer l'horodatage lorsque le focus était perdu, puis dans getView () lors de la recréation de l'élément de liste. ) pour le restituer à l’EditText en question.

Vous pouvez également récupérer le texte de l'instance précédente de EditText à ce stade et le transférer vers la nouvelle instance.

private class MyAdapter<Type> extends ArrayAdapter<String>
    implements OnFocusChangeListener
{
    private EditText mText;
    private long mTextLostFocusTimestamp;
    private LayoutInflater mLayoutInflater;

    public MyAdapter(Context context, int resource, int textResourceId, ArrayList<String> data, LayoutInflater li) {
        super(context, resource, textResourceId, data);
        mLayoutInflater = li;
        mTextLostFocusTimestamp = -1;
    }

    private void reclaimFocus(View v, long timestamp) {
        if (timestamp == -1)
            return;
        if ((System.currentTimeMillis() - timestamp) < 250)
            v.requestFocus();
    }

    @Override public View getView (int position, View convertView, ViewGroup parent)
    {
        View v = mLayoutInflater.inflate(R.layout.mylayout, parent, false);

        EditText newText = (EditText) v.findViewById(R.id.email);
        if (mText != null)
            newText.setText(mText.getText());
        mText = newText;
        mText.setOnFocusChangeListener(this);
        reclaimFocus(mText, mTextLostFocusTimestamp);

        return v;
    }

    @Override public void onFocusChange(View v, boolean hasFocus) {
        if ((v == mText) && !hasFocus)
            mTextLostFocusTimestamp = System.currentTimeMillis();
    }
}
9
sheltond

Si le editText à l'intérieur de listView s'assure simplement que vous gonflez la vue dans la méthode getView de cette manière.


        if (convertView == null)
        convertView = LayoutInflater.from(context).inflate(R.layout.yourItemListLayout,
                parent, false);   

Edit: ce travail pour certains mobiles, je n’utilise pas tous la réponse de M. Frank ci-dessus.

1
Samer Kador

Dans AndroidManifest.xml, utilisez adjustNothing dans l’activité contenant les vues.

<activity
            Android:name=".ActivityName"
            Android:windowSoftInputMode="adjustNothing">
1

Vous devez tester ce code sur un périphérique avec un clavier matériel toujours visible. Le comportement peut également se produire ici.

Pour éviter cela, vous pouvez avoir le clavier toujours visible .. mais ce n'est pas très facile, comme vous pouvez le voir avec ce fil:

https://groups.google.com/forum/#!topic/Android-developers/FyENeEdmYC0

Théoriquement, vous devrez peut-être créer votre propre clavier Android (bien que vous utilisiez comme base le clavier Android), comme décrit ici: Android: Comment rendre le clavier toujours visible?

1
neteinstein

Pour ceux qui viennent ici avec Xamarin ou Xamarin.Forms:

J'ai eu le même problème aussi, mais seulement avec Android 5.x - toutes les versions plus récentes, y compris 8.1, ont bien fonctionné.

Evidemment, sheltond avait raison en disant:

Dans mon cas, cela se produit car lorsque ListView est redimensionné, il recrée tous les éléments de la liste (c.-à-d. Qu'il appelle à nouveau getView () pour chaque élément de la liste visible).

Ma liste a également été redimensionnée et non, la solution de Frank de définir windowSoftInputMode="adjustPan" n’était pas une option pour moi, car cela signifie que le clavier déplace partiellement la liste en dehors de l’écran.

Tout ce que je devais faire après des heures de débogage de focus était de définir la stratégie de mise en cache de cellules de Xamarin Forms ListView:

De

CachingStrategy="RecycleElement"

À

CachingStrategy="RetainElement"

Cela empêchera les cellules d'être recréées. Toutefois, cela pourrait entraîner de mauvaises performances et une consommation de mémoire importante pour les listes volumineuses. Être conscient.

0
Waescher

Ajoutez Android: windowSoftInputMode = "adjustResize" dans l'activité contenant la liste ou EditText. Cela résoudra votre problème.

<activity Android:name=".MainActivity"
        Android:windowSoftInputMode="adjustResize">
</activity>
0
Jibin Anto

Ce gars avait le même problème et plus encore. Il l'a résolu en utilisant un ScrollView et un LinearLayout au lieu d'un ListView. 

0
Martin Stone