104 votes

Comment masquer un élément dans un Spinner Android ?

Je cherche un moyen de masquer un élément dans un widget spinner Android. Cela permettrait de simuler un spinner sans éléments sélectionnés, et de s'assurer que le callback onItemSelected() est toujours appelé pour chaque élément sélectionné (si l'élément caché est l'élément "courant"). Normalement, il y a toujours un élément dans le spinner qui ne génère pas de callback, à savoir l'élément courant.

Il y a un peu de code sur stackoverflow pour savoir comment désactiver (griser) des éléments, mais pas comment cacher complètement des éléments comme s'ils n'existaient pas.

Après de nombreuses expérimentations, j'ai trouvé une solution un peu bricolée qui fonctionne sur diverses plateformes Android, anciennes et nouvelles. Elle présente quelques inconvénients cosmétiques mineurs qui sont difficiles à remarquer. J'aimerais quand même entendre parler d'une solution plus officielle, autre que "ne faites pas ça avec un spinner".

Cela cache toujours le premier élément du spinner, mais pourrait assez facilement être étendu pour cacher un élément arbitraire ou plus d'un élément. Ajoutez un élément fictif contenant une chaîne vide au début de votre liste d'éléments du compteur rotatif. Vous pouvez définir la sélection actuelle du compteur à l'élément 0 avant l'ouverture de la boîte de dialogue du compteur, ce qui simulera un compteur non sélectionné.

Exemple de configuration de Spinner avec une surcharge de la méthode ArrayAdapter :

List<String> list = new ArrayList<String>();
list.add("");   //  Initial dummy entry
list.add("string1");
list.add("string2");
list.add("string3");

// Populate the spinner using a customized ArrayAdapter that hides the first (dummy) entry
ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, list) {
    @Override
    public View getDropDownView(int position, View convertView, ViewGroup parent)
    {
        View v = null;

        // If this is the initial dummy entry, make it hidden
        if (position == 0) {
            TextView tv = new TextView(getContext());
            tv.setHeight(0);
            tv.setVisibility(View.GONE);
            v = tv;
        }
        else {
            // Pass convertView as null to prevent reuse of special case views
            v = super.getDropDownView(position, null, parent);
        }

        // Hide scroll bar because it appears sometimes unnecessarily, this does not prevent scrolling 
        parent.setVerticalScrollBarEnabled(false);
        return v;
    }
};

dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mySpinner.setAdapter(dataAdapter);

0 votes

Qu'avez-vous trouvé sur les autres sites Internet ? Qu'avez-vous essayé jusqu'à présent ?

0 votes

Désolé lah, je ne sais pas comment faire.

0 votes

Belle solution ! Mais je pense que le tv.setVisibility(View.GONE); est inutile. La commenter ne semble pas faire de différence (visuelle), du moins sous Android 4.4.2/KitKit (sur un LG/Google Nexus 4).

53voto

Aebsubis Points 201

Pour masquer un élément arbitraire ou plus d'un élément, je pense que vous pouvez implémenter votre propre adaptateur et définir l'index (ou la liste des index) que vous souhaitez masquer.

public class CustomAdapter extends ArrayAdapter<String> {

     private int hidingItemIndex;

     public CustomAdapter(Context context, int textViewResourceId, String[] objects, int hidingItemIndex) {
         super(context, textViewResourceId, objects);
         this.hidingItemIndex = hidingItemIndex;
     }

     @Override
     public View getDropDownView(int position, View convertView, ViewGroup parent) {
         View v = null;
         if (position == hidingItemIndex) {
             TextView tv = new TextView(getContext());
             tv.setVisibility(View.GONE);
             v = tv;
         } else {
             v = super.getDropDownView(position, null, parent);
         }
         return v;
     }
 }

Et utilisez votre adaptateur personnalisé lorsque vous créez la liste d'éléments.

List<String> list = new ArrayList<String>();
list.add("");   //  Initial dummy entry
list.add("string1");
list.add("string2");
list.add("string3");

int hidingItemIndex = 0;

CustomAdapter dataAdapter = new CustomAdapter(this, android.R.layout.simple_spinner_item, list, hidingItemIndex);

dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mySpinner.setAdapter(dataAdapter);

(Je n'ai pas testé le code) J'espère que cela vous aidera.

1 votes

Ce n'est pas une solution. La mise à jour de la question fournit le code correct.

14 votes

Sans tv.setHeight(0), le TextView est toujours visible.

0 votes

Bonjour, j'ai utilisé ce code pour cacher le premier élément dans mon spinner, cela fonctionne bien, mon spinner me montrera le deuxième élément, mais quand je clique sur ce deuxième élément, le texte sur cet élément sera défini sur mon spinner, je ne veux pas montrer de texte sur mon spinner quand je clique sur cet élément, s'il vous plaît guidez-moi ?

23voto

Romich Points 41

Il est plus facile de cacher un élément en fin de liste en tronquant la liste.

Mais vous devez d'abord le sélectionner pour qu'il apparaisse dans le spinner, puis vérifier si la sélection a été changée en l'un des éléments affichés.

List<String> list = new ArrayList<String>();
list.add("string1");
list.add("string2");
list.add("string3");
list.add("[Select one]");
final int listsize = list.size() - 1;

ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(this,android.R.layout.simple_spinner_item, list) {
    @Override
    public int getCount() {
        return(listsize); // Truncate the list
    }
};

dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mySpinner.setAdapter(dataAdapter);
mySpinner.setSelection(listsize); // Hidden item to appear in the spinner

3 votes

J'ai cherché pendant une demi-heure à trouver une approche propre, et celle-ci est de loin la meilleure. Il suffit de tronquer la liste, mais l'élément existe réellement. Excellent.

1 votes

Cela ne semble pas fonctionner dans Lollipop, le test [Select one] ne s'affiche pas initialement dans le Spinner. Le même code sur les anciennes versions d'Android semble faire ce que nous voulons tous.

1 votes

Le texte du spinner est changé en 'String3' lors du changement d'orientation, même si le spinner n'est pas modifié. @Romich

1voto

K.D. Points 1

Juste pour l'intérêt, j'ai fait une solution pour utiliser "Prompt" comme un indice. Ce code est fait pour Xamarin.Android mais il pourrait être parfaitement porté en Java en 10 minutes. Utilisez-le comme un simple ArrayAdapter sans ajouter d'éléments indexés à 0 ou au nombre dans le tableau source. Il définit également SpinnerGeolocation.SelectedItemId à -1 lorsque rien n'est choisi ( hint est l'élément actuel).

public class ArrayAdapterWithHint<T>: ArrayAdapter<T>
{
    protected bool HintIsSet = false;
    protected int HintResource = 0;

    public ArrayAdapterWithHint(Context context, int textViewResourceId,
                   T[] objects)
        : base(context, textViewResourceId, objects)
    {
    }
    public ArrayAdapterWithHint(Context context, int hintResource,
                   int textViewResourceId, T[] objects)
        : base(context, textViewResourceId, objects)
    {
        HintResource = hintResource;
    }
    public ArrayAdapterWithHint(Context context, int textViewResourceId,
             IList<T> objects)
        : base(context, textViewResourceId, objects)
    {
    }
    public ArrayAdapterWithHint(Context context, int hintResource,
                    int textViewResourceId, IList<T> objects)
        : base(context, textViewResourceId, objects)
    {
        HintResource = hintResource;
    }

    public override View GetDropDownView(int position, View convertView,
                ViewGroup parent)
    {
        if (HintIsSet)
            return base.GetDropDownView(position + 1,
                               convertView, parent);
        return base.GetDropDownView(position, convertView, parent);
    }

    public override View GetView(int position, View convertView,
                      ViewGroup parent)
    {
        if (!HintIsSet && parent is Spinner && 
                    !string.IsNullOrWhiteSpace((parent as Spinner).Prompt))
        {
            Insert((parent as Spinner).Prompt, 0);
            HintIsSet = true;
            (parent as Spinner).SetSelection(base.Count - 1);
        }
        if (HintIsSet && position >= base.Count - 1)
        {
            View hintView = base.GetView(0, convertView, parent);
            if (hintView is TextView)
                (hintView as TextView).SetTextAppearance(
                                                     Context, HintResource);
            return hintView;
        }
        if (HintIsSet && position < base.Count - 1)
            return base.GetView(position + 1, convertView, parent);
        return base.GetView(position, convertView, parent);
    }

    public override long GetItemId(int position)
    {
        if (HintIsSet)
        {
            if (position >= base.Count - 1)
                return -1;
            return position;
        }
        return base.GetItemId(position);
    }

    public override int Count
    {
        get
        {
            return base.Count > 0 && HintIsSet ? base.Count - 1 : base.Count;
        }
    }
}

0 votes

Quelqu'un peut-il examiner mon pregunta ?

0voto

Akhilesh Points 14

Je pense qu'il sera préférable de mettre la validation sur la liste de tableaux plutôt que sur le Spinner car une fois l'élément filtré, il sera sûr d'être ajouté dans le Spinner.

0voto

Vajid Points 83

J'ai trouvé cette solution qui a résolu mon problème.

final Spinner mySpinner = (Spinner)findViewById(R.id.spinner_triptype);

   final ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,R.layout.spinner_item, R.id.weekofday, triptype_initial);

   final ArrayAdapter<String> adapter_temp = new ArrayAdapter<String>
(this,R.layout.spinner_item, R.id.weekofday, triptype_array);

   mySpinner.setAdapter(adapter);
    mySpinner.setOnTouchListener(new View.OnTouchListener() {
       @Override
       public boolean onTouch(View v, MotionEvent event) {
       // display your error popup here
        if(flag_spinner_isFirst){
           mySpinner.setAdapter(adapter_temp);
           flag_spinner_isFirst = false;
          }
           v.onTouchEvent(event);
           return true;

       }
    });

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