35 votes

Bug du système d'exploitation Android avec certains appareils fonctionnant sous Jelly Bean/4.2.1 - TextView.setError(CharSequence error) Icône manquante

Certains appareils fonctionnant sous Jelly Bean (4.2.1), mais pas tous, semblent ne pas avoir l'icône d'erreur en forme de point d'exclamation qui devrait apparaître sur un message d'erreur. TextView (ou, plus communément, un EditText ) sur lequel une erreur a été définie par l'intermédiaire de TextView.setError(CharSequence error) .

enter image description hereenter image description here

Le Galaxy Nexus ne semble pas avoir l'icône.

L'effet est que le statut d'erreur défini par setError n'est apparente que lorsque le EditText se concentre. Ce qui fait que setError(...) beaucoup moins utile, car il est souvent utilisé pour encourager les utilisateurs à revenir sur le site en question. EditText pour résoudre un problème. Par exemple, vous avez un écran de connexion standard avec des entrées de formulaire de nom d'utilisateur et de mot de passe qui sont validées lorsque l'utilisateur clique sur un bouton d'envoi. Un message d'erreur de validation défini sur le formulaire du nom d'utilisateur ne s'affichera pas à moins que l'utilisateur ne clique à nouveau sur ce formulaire - ce que l'icône d'erreur est censée l'encourager à faire !

Pour tester : (Il existe peut-être un EditText plus facilement accessible, mais celui-ci est très largement disponible)

  1. Ouvrir les paramètres
  2. Sélectionnez "Ajouter un compte" (dans "Comptes et synchronisation" sur les appareils plus anciens).
  3. Sélectionnez "Google" comme type de compte
  4. Sélectionnez "Existant" (après avoir cliqué sur "Suivant" et "S'identifier" sur les appareils plus anciens).
  5. Quitter l'"Email EditText vide, cliquez sur le bouton "Mot de passe EditText

À ce stade, un message d'erreur est envoyé à l'adresse "Email EditText en disant qu'il ne peut pas être vierge. Sur les appareils qui ne présentent pas ce problème, l'icône d'erreur habituelle s'affiche, qui se transforme en message d'erreur complet lorsque l'icône d'erreur s'affiche. EditText se concentre. Sur les Galaxy Nexus fonctionnant sous Jelly Bean, aucune icône n'est affichée et l'erreur n'est visible que lorsque la fonction "Email" est activée. EditText a de nouveau la mise au point, et il n'y a toujours pas d'icône à ce moment-là.

Cela ressemble à un bogue, mais je voulais vérifier si d'autres personnes pouvaient le reproduire, avaient des idées sur ce que le problème pouvait être, et avaient une bonne solution de contournement.

Utilisation setError(CharSequence error, Drawable icon) devrait probablement régler le problème, mais il serait bon de pouvoir utiliser le graphique d'erreur standard dans les différentes versions d'Android.

18voto

Oleg Vaskevich Points 4216

Solution temporaire ! EditTextErrorFixed.java

Bien qu'il s'agisse d'un bogue du SDK, j'ai réussi à utiliser des méthodes de réflexion pour que l'icône fonctionne comme prévu. J'ai vérifié que cela fonctionne avec les versions 4.2 et 4.2.1 et j'ai vérifié que cela fonctionne sur mon Galaxy Nexus mis à jour.

La source peut être trouvée ici.

La capture d'écran montre que l'icône du bas EditTextErrorFixed persiste même si la focalisation change. En outre, il incorpore un autre correctif : si l'utilisateur appuie sur la touche "Suppr" d'un champ de saisie déjà vide, le champ de saisie est supprimé. EditText l'erreur disparaît (un autre bug ?).

Demo image

Pour plus de commodité, voici le EditTextErrorFixed la classe peut facilement être utilisée en XML :

package com.olegsv.showerrorfixeddemo;

import android.content.Context;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.widget.EditText;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * EditText which addresses issues with the error icon
 * (http://stackoverflow.com/q/13756978/832776) and also the error icon
 * disappearing on pressing delete in an empty EditText
 */
public class EditTextErrorFixed extends EditText {
    public EditTextErrorFixed(Context context) {
        super(context);
    }

    public EditTextErrorFixed(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public EditTextErrorFixed(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    /**
     * Don't send delete key so edit text doesn't capture it and close error
     */
    @Override
    public boolean onKeyPreIme(int keyCode, KeyEvent event) {
        if (TextUtils.isEmpty(getText().toString()) && keyCode == KeyEvent.KEYCODE_DEL)
            return true;
        else
            return super.onKeyPreIme(keyCode, event);
    }

    /**
     * Keep track of which icon we used last
     */
    private Drawable lastErrorIcon = null;

    /**
     * Resolve an issue where the error icon is hidden under some cases in JB
     * due to a bug http://code.google.com/p/android/issues/detail?id=40417
     */
    @Override
    public void setError(CharSequence error, Drawable icon) {
        super.setError(error, icon);
        lastErrorIcon = icon;

        // if the error is not null, and we are in JB, force
        // the error to show
        if (error != null /* !isFocused() && */) {
            showErrorIconHax(icon);
        }
    }

    /**
     * In onFocusChanged() we also have to reshow the error icon as the Editor
     * hides it. Because Editor is a hidden class we need to cache the last used
     * icon and use that
     */
    @Override
    protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
        super.onFocusChanged(focused, direction, previouslyFocusedRect);
        showErrorIconHax(lastErrorIcon);
    }

    /**
     * Use reflection to force the error icon to show. Dirty but resolves the
     * issue in 4.2
     */
    private void showErrorIconHax(Drawable icon) {
        if (icon == null)
            return;

        // only for JB 4.2 and 4.2.1
        if (android.os.Build.VERSION.SDK_INT != Build.VERSION_CODES.JELLY_BEAN &&
                android.os.Build.VERSION.SDK_INT != Build.VERSION_CODES.JELLY_BEAN_MR1)
            return;

        try {
            Class<?> textview = Class.forName("android.widget.TextView");
            Field tEditor = textview.getDeclaredField("mEditor");
            tEditor.setAccessible(true);
            Class<?> editor = Class.forName("android.widget.Editor");
            Method privateShowError = editor.getDeclaredMethod("setErrorIcon", Drawable.class);
            privateShowError.setAccessible(true);
            privateShowError.invoke(tEditor.get(this), icon);
        } catch (Exception e) {
            // e.printStackTrace(); // oh well, we tried
        }
    }
}

0voto

j2emanue Points 3456

Je sais qu'il existe déjà une solution. C'est juste que j'essaie d'éviter la réflexion à tout prix sur Android. Si vous êtes d'accord avec la réflexion, allez-y, mais essayez d'abord ma solution ci-dessous car elle pourrait résoudre le problème sans avoir à sous-classer et à réfléchir.

Drawable d= getResources().getDrawable(R.drawable.ic_launcher);
            d.setBounds(0, 0, 
                    d.getIntrinsicWidth(), d.getIntrinsicHeight());

            et.setError("my error",d);

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X