70 votes

Android Spinner avec choix multiple

Comment créer un spinner qui permet de choisir plusieurs éléments, c'est-à-dire un spinner avec des cases à cocher ?

1 votes

AFAIK Spinner n'a pas de mode de choix multiple.

0 votes

Et comment voulez-vous afficher les valeurs sélectionnées dans le spinner ?

0 votes

Je veux dire comment mettre en œuvre ce qui suit : un widget qui fonctionne comme un spinner mais qui affiche un dialogue avec des cases à cocher et permet un choix multiple.

162voto

Destil Points 3673

J'ai écrit une implémentation personnalisée de MultiSpinner. Il ressemble à un spinner normal, mais il comporte des cases à cocher au lieu de boutons radio. Les valeurs sélectionnées sont affichées sur le spinner divisées par des virgules. Toutes les valeurs sont cochées par défaut. Essayez-le :

package cz.destil.settleup.gui;

public class MultiSpinner extends Spinner implements
        OnMultiChoiceClickListener, OnCancelListener {

    private List<String> items;
    private boolean[] selected;
    private String defaultText;
    private MultiSpinnerListener listener;

    public MultiSpinner(Context context) {
        super(context);
    }

    public MultiSpinner(Context arg0, AttributeSet arg1) {
        super(arg0, arg1);
    }

    public MultiSpinner(Context arg0, AttributeSet arg1, int arg2) {
        super(arg0, arg1, arg2);
    }

    @Override
    public void onClick(DialogInterface dialog, int which, boolean isChecked) {
        if (isChecked)
            selected[which] = true;
        else
            selected[which] = false;
    }

    @Override
    public void onCancel(DialogInterface dialog) {
        // refresh text on spinner
        StringBuffer spinnerBuffer = new StringBuffer();
        boolean someSelected = false;
        for (int i = 0; i < items.size(); i++) {
            if (selected[i] == true) {
                spinnerBuffer.append(items.get(i));
                spinnerBuffer.append(", ");
                someSelected = true;
            } 
        }
        String spinnerText;
        if (someSelected) {
            spinnerText = spinnerBuffer.toString();
            if (spinnerText.length() > 2)
                spinnerText = spinnerText.substring(0, spinnerText.length() - 2);
        } else {
            spinnerText = defaultText;
        }
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(getContext(),
                android.R.layout.simple_spinner_item,
                new String[] { spinnerText });
        setAdapter(adapter);
        listener.onItemsSelected(selected);
    }

    @Override
    public boolean performClick() {
        AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
        builder.setMultiChoiceItems(
                items.toArray(new CharSequence[items.size()]), selected, this);
        builder.setPositiveButton(android.R.string.ok,
                new DialogInterface.OnClickListener() {

                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.cancel();
                    }
                });
        builder.setOnCancelListener(this);
        builder.show();
        return true;
    }

    public void setItems(List<String> items, String allText,
            MultiSpinnerListener listener) {
        this.items = items;
        this.defaultText = allText;
        this.listener = listener;

        // all selected by default
        selected = new boolean[items.size()];
        for (int i = 0; i < selected.length; i++)
            selected[i] = true;

        // all text on the spinner
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(getContext(),
                android.R.layout.simple_spinner_item, new String[] { allText });
        setAdapter(adapter);
    }

    public interface MultiSpinnerListener {
        public void onItemsSelected(boolean[] selected);
    }
}

Vous l'utilisez dans un XML comme celui-ci :

<cz.destil.settleup.gui.MultiSpinner android:id="@+id/multi_spinner" />

Et vous lui passez des données en Java comme ceci :

MultiSpinner multiSpinner = (MultiSpinner) findViewById(R.id.multi_spinner);
multiSpinner.setItems(items, getString(R.string.for_all), this);

Vous devez également implémenter l'écouteur, qui renverra le tableau de même longueur, avec true ou false pour montrer le sélectionné ou le non-sélectionné

public void onItemsSelected(boolean[] selected);

2 votes

Comment obtenez-vous les index sélectionnés à partir de votre composant ? Je suis capable de l'utiliser mais comment puis-je obtenir les éléments sélectionnés ? Merci pour votre aide.

1 votes

Il suffit d'exposer le tableau selected[] via un getter public.

2 votes

Fonctionne très bien ! Un code génial. Merci d'avoir publié une liste complète.

14voto

vault Points 719

Je voudrais juste montrer une version alternative du MultiSpinner de @Destil (merci pour votre code inspirant) qui permet d'utiliser "Android:entries" en xml, comme un spinner.

Il n'affiche pas initialement un texte par défaut, comme "choisir un", mais vous pouvez facilement l'obtenir en définissant un paramètre supplémentaire ArrayAdapter dans le constructeur.

MultiSpinner.java

package com.example.helloworld;

import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnMultiChoiceClickListener;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.widget.ArrayAdapter;
import android.widget.Spinner;

/**
 * Inspired by: http://stackoverflow.com/a/6022474/1521064
 */
public class MultiSpinner extends Spinner {

    private CharSequence[] entries;
    private boolean[] selected;
    private MultiSpinnerListener listener;

    public MultiSpinner(Context context, AttributeSet attrs) {
        super(context, attrs);

        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MultiSpinner);
        entries = a.getTextArray(R.styleable.MultiSpinner_android_entries);
        if (entries != null) {
            selected = new boolean[entries.length]; // false-filled by default
        }
        a.recycle();
    }

    private OnMultiChoiceClickListener mOnMultiChoiceClickListener = new OnMultiChoiceClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which, boolean isChecked) {
            selected[which] = isChecked;
        }
    };

    private DialogInterface.OnClickListener mOnClickListener = new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            // build new spinner text & delimiter management
            StringBuffer spinnerBuffer = new StringBuffer();
            for (int i = 0; i < entries.length; i++) {
                if (selected[i]) {
                    spinnerBuffer.append(entries[i]);
                    spinnerBuffer.append(", ");
                }
            }

            // Remove trailing comma
            if (spinnerBuffer.length() > 2) {
                spinnerBuffer.setLength(spinnerBuffer.length() - 2);
            }

            // display new text
            ArrayAdapter<String> adapter = new ArrayAdapter<String>(getContext(),
                    android.R.layout.simple_spinner_item,
                    new String[] { spinnerBuffer.toString() });
            setAdapter(adapter);

            if (listener != null) {
                listener.onItemsSelected(selected);
            }

            // hide dialog
            dialog.dismiss();
        }
    };

    @Override
    public boolean performClick() {
        new AlertDialog.Builder(getContext())
                .setMultiChoiceItems(entries, selected, mOnMultiChoiceClickListener)
                .setPositiveButton(android.R.string.ok, mOnClickListener)
                .show();
        return true;
    }

    public void setMultiSpinnerListener(MultiSpinnerListener listener) {
        this.listener = listener;
    }

    public interface MultiSpinnerListener {
        public void onItemsSelected(boolean[] selected);
    }
}

attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="MultiSpinner">
        <attr name="android:entries" />
    </declare-styleable>
</resources>

layout_main_activity.xml

<com.example.helloworld.MultiSpinner
    android:id="@+id/multispinner"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:entries="@array/multispinner_entries" />

9voto

Vikas Patidar Points 19772

Pour autant que je sache Spinner ne dispose pas d'un mode de choix multiple. Au lieu de cela, vous pouvez créer un ImageButton et définissez une flèche vers le bas traçable sur le côté droit et sur l'événement de clic, vous pouvez ouvrir une fenêtre Dialog avoir des éléments avec les cases à cocher multiples.

3voto

Andrea Carrer Points 1570

Merci pour le post ! Excellente solution. J'ai apporté une petite modification à la classe (méthode setItems) pour permettre aux utilisateurs de définir les éléments déjà sélectionnés au lieu de sélectionner tous les éléments à true par défaut.

public void setItems(
    List<String> items,
    List<String> itemValues, 
    String selectedList,
    String allText,
    MultiSpinnerListener listener) {
        this.items = items;
        this.defaultText = allText;
        this.listener = listener;

        String spinnerText = allText;

        // Set false by default
        selected = new boolean[itemValues.size()];
        for (int j = 0; j < itemValues.size(); j++)
            selected[j] = false;

        if (selectedList != null) {
            spinnerText = "";
            // Extract selected items
            String[] selectedItems = selectedList.trim().split(",");

            // Set selected items to true
            for (int i = 0; i < selectedItems.length; i++)
                for (int j = 0; j < itemValues.size(); j++)
                    if (selectedItems[i].trim().equals(itemValues.get(j))) {
                        selected[j] = true;
                        spinnerText += (spinnerText.equals("")?"":", ") + items.get(j);
                        break;
                }
    }

        // Text for the spinner
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(getContext(),
            android.R.layout.simple_spinner_item, new String[] { spinnerText });
        setAdapter(adapter);
}

0 votes

Ce qui doit figurer dans la liste itemValues ?

1 votes

@eoinzy Supposons que vous ayez une liste de pays. Dans itemValues il y a les valeurs des ID (par exemple "us", "uk", "de", "ch", ou "1", "2", "3", "4"), dans items il y a les descriptions ("USA, "United Kingdom", "Germany", "Switzerland").

0 votes

J'ai réussi à faire fonctionner le multi spinner, mais maintenant, comment puis-je extraire les itemValues sélectionnées dans une chaîne de caractères avec virgule ? '1,2,4,7'

2voto

Pratik Butani Points 4290

Vous pouvez vérifier une bibliothèque simple MultiSelectSpinner

Vous pouvez simplement suivre les étapes suivantes :

multiSelectSpinnerWithSearch.setItems(listArray1, new MultiSpinnerListener() {
    @Override
    public void onItemsSelected(List<KeyPairBoolData> items) {
        for (int i = 0; i < items.size(); i++) {
            if (items.get(i).isSelected()) {
                Log.i(TAG, i + " : " + items.get(i).getName() + " : " + items.get(i).isSelected());
            }
        }
    }
});

Le site listArray1 sera votre tableau.

Consultez l'exemple complet ici dans Comment faire

0 votes

Poster le problème sur github @Hasini

1 votes

Pourquoi il est nécessaire d'utiliser KeyPairBoolData Ne pouvons-nous pas utiliser un tableau de chaînes dans votre dépendance ?

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