Comment faire un Android Spinner avec le texte initial "Select One"?

569

Je veux utiliser un Spinner qui initialement (lorsque l'utilisateur n'a pas encore fait de sélection) affiche le texte "Select One". Lorsque l'utilisateur clique sur la double flèche, la liste des éléments s'affiche et l'utilisateur sélectionne l'une des options. Une fois que l'utilisateur a effectué une sélection, l'élément sélectionné est affiché dans le Spinner au lieu de "Sélectionner un".

J'ai le code suivant pour créer un Spinner:

String[] items = new String[] {"One", "Two", "Three"};
Spinner spinner = (Spinner) findViewById(R.id.mySpinner);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
            android.R.layout.simple_spinner_item, items);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);

Avec ce code, l'élément "One" est initialement affiché. Je pourrais simplement ajouter un nouvel élément "Select One" aux éléments, mais ensuite "Select One" serait également affiché dans la liste déroulante comme premier élément, ce qui n'est pas ce que je veux.

Comment puis-je résoudre ce problème?

Pieter Kuijpers
la source
6
La solution parfaite réside dans cette question: stackoverflow.com/questions/9863378/… Il suffit de remplacer la méthode getDropDownView ().
Sourab Sharma
Avez-vous essayé de régler le premier élément de votre adaptateur sur "Select One"?
IgorGanapolsky
[Voici une autre excellente solution!] [1] [1]: stackoverflow.com/questions/9863378/…
AirtonCarneiro
spinner réutilisable: github.com/henrychuangtw/ReuseSpinner
HenryChuang

Réponses:

255

Voici une solution générale qui remplace la Spinnervue. Il remplace setAdapter()pour définir la position initiale à -1, et remplace le fourni SpinnerAdapterpour afficher la chaîne d'invite pour une position inférieure à 0.

Cela a été testé sur Android 1.5 à 4.2, mais attention à l'acheteur! Parce que cette solution repose sur la réflexion pour appeler le privé AdapterView.setNextSelectedPositionInt()et AdapterView.setSelectedPositionInt(), il n'est pas garanti de fonctionner dans les futures mises à jour du système d'exploitation. Il semble probable que ce sera le cas, mais ce n'est en aucun cas garanti.

Normalement, je ne tolérerais pas quelque chose comme ça, mais cette question a été posée suffisamment de fois et cela semble être une demande suffisamment raisonnable pour que je pense publier ma solution.

/**
 * A modified Spinner that doesn't automatically select the first entry in the list.
 *
 * Shows the prompt if nothing is selected.
 *
 * Limitations: does not display prompt if the entry list is empty.
 */
public class NoDefaultSpinner extends Spinner {

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

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

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

    @Override
    public void setAdapter(SpinnerAdapter orig ) {
        final SpinnerAdapter adapter = newProxy(orig);

        super.setAdapter(adapter);

        try {
            final Method m = AdapterView.class.getDeclaredMethod(
                               "setNextSelectedPositionInt",int.class);
            m.setAccessible(true);
            m.invoke(this,-1);

            final Method n = AdapterView.class.getDeclaredMethod(
                               "setSelectedPositionInt",int.class);
            n.setAccessible(true);
            n.invoke(this,-1);
        } 
        catch( Exception e ) {
            throw new RuntimeException(e);
        }
    }

    protected SpinnerAdapter newProxy(SpinnerAdapter obj) {
        return (SpinnerAdapter) java.lang.reflect.Proxy.newProxyInstance(
                obj.getClass().getClassLoader(),
                new Class[]{SpinnerAdapter.class},
                new SpinnerAdapterProxy(obj));
    }



    /**
     * Intercepts getView() to display the prompt if position < 0
     */
    protected class SpinnerAdapterProxy implements InvocationHandler {

        protected SpinnerAdapter obj;
        protected Method getView;


        protected SpinnerAdapterProxy(SpinnerAdapter obj) {
            this.obj = obj;
            try {
                this.getView = SpinnerAdapter.class.getMethod(
                                 "getView",int.class,View.class,ViewGroup.class);
            } 
            catch( Exception e ) {
                throw new RuntimeException(e);
            }
        }

        public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
            try {
                return m.equals(getView) && 
                       (Integer)(args[0])<0 ? 
                         getView((Integer)args[0],(View)args[1],(ViewGroup)args[2]) : 
                         m.invoke(obj, args);
            } 
            catch (InvocationTargetException e) {
                throw e.getTargetException();
            } 
            catch (Exception e) {
                throw new RuntimeException(e);
            }
        }

        protected View getView(int position, View convertView, ViewGroup parent) 
          throws IllegalAccessException {

            if( position<0 ) {
                final TextView v = 
                  (TextView) ((LayoutInflater)getContext().getSystemService(
                    Context.LAYOUT_INFLATER_SERVICE)).inflate(
                      android.R.layout.simple_spinner_item,parent,false);
                v.setText(getPrompt());
                return v;
            }
            return obj.getView(position,convertView,parent);
        }
    }
}
emmby
la source
7
@emmby Avez-vous une idée de comment effacer la sélection après que l'utilisateur l'a définie? J'ai essayé de refactoriser les deux appels invoke () dans une méthode clearSelection (), mais cela ne fonctionne pas vraiment. Bien que la liste contextuelle affiche l'élément précédemment sélectionné comme non sélectionné, le widget spinner l'affiche toujours comme sélectionné, et si l'utilisateur sélectionne à nouveau le même élément, onItemSelected () n'est pas appelé.
Qwertie
3
certains pourraient-ils expliquer comment utiliser la classe ci-dessus?
Bishan
4
Cette solution n'est pas parfaite à 100% sur Android 4.2 (Cyanogenmod 10.1), en utilisant android: entries. La hauteur du TextView gonflé est inférieure à la hauteur de la ressource que l'adaptateur par défaut gonfle. Donc, lorsque vous sélectionnez réellement une option, la hauteur augmente, ~ 10px dans mon Galaxy S, ce qui n'est pas acceptable. J'ai essayé plusieurs choses (gravité, rembourrage, marge, etc.) et aucune n'a fonctionné de manière fiable sur tous les appareils, donc je vais opter pour une solution différente.
Maragues
3
@DavidDoria Vous devez utiliser la classe NoDefaultSpinner dans votre fichier de mise en page. Copiez la source ci-dessus dans votre projet, par exemple dans le package com.example.customviews. Maintenant, dans votre mise en page xml, au lieu de <Spinner ...> utilisez <com.example.customviews.NoDefaultSpinner ...> Le reste du code peut rester le même. N'oubliez pas d'ajouter l'attribut android: prompt à la vue <com.example.customviews.NoDefaultSpinner> dans votre mise en page.
Ridcully
2
@emmby spinnerBrand.setSelection (-1); ne fonctionne pas
Sachin C
291

Ce que vous pouvez faire, c'est décorer votre SpinnerAdapteravec celui qui présente une «option de sélection ...» initialement pour le Spinner à afficher sans rien sélectionné.

Voici un exemple de travail testé pour Android 2.3 et 4.0 (il n'utilise rien dans la bibliothèque de compatibilité, donc ça devrait aller pendant un certain temps) Comme c'est un décorateur, il devrait être facile de moderniser le code existant et ça marche bien avec CursorLoaders aussi. (Échangez le curseur sur l'enveloppé cursorAdapterbien sûr ...)

Il existe un bogue Android qui rend la réutilisation des vues un peu plus difficile. (Vous devez donc utiliser le setTagou quelque chose d'autre pour vous assurer que votre convertViewest correct.) Spinner ne prend pas en charge plusieurs types de vue

Notes de code: 2 constructeurs

Cela vous permet d'utiliser une invite standard ou de définir votre propre «rien sélectionné» comme première ligne, ou les deux, ou aucune. (Remarque: certains thèmes affichent un DropDown pour un Spinner au lieu d'une boîte de dialogue. Le Dropdown n'affiche normalement pas l'invite)

Vous définissez une mise en page pour qu'elle ressemble à une invite, par exemple grisée ...

Initial rien sélectionné

À l'aide d'une invite standard (notez que rien n'est sélectionné):

Avec une invite standard

Ou avec une invite et quelque chose de dynamique (aurait pu aussi avoir aucune invite):

Invite et rien sélectionné

Utilisation dans l'exemple ci-dessus

Spinner spinner = (Spinner) findViewById(R.id.spinner);
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this, R.array.planets_array, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setPrompt("Select your favorite Planet!");

spinner.setAdapter(
      new NothingSelectedSpinnerAdapter(
            adapter,
            R.layout.contact_spinner_row_nothing_selected,
            // R.layout.contact_spinner_nothing_selected_dropdown, // Optional
            this));

contact_spinner_row_nothing_selected.xml

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@android:id/text1"
    style="?android:attr/spinnerItemStyle"
    android:singleLine="true"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:ellipsize="marquee"
    android:textSize="18sp"
    android:textColor="#808080"
    android:text="[Select a Planet...]" />

NothingSelectedSpinnerAdapter.java

import android.content.Context;
import android.database.DataSetObserver;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListAdapter;
import android.widget.SpinnerAdapter;

/**
 * Decorator Adapter to allow a Spinner to show a 'Nothing Selected...' initially
 * displayed instead of the first choice in the Adapter.
 */
public class NothingSelectedSpinnerAdapter implements SpinnerAdapter, ListAdapter {

    protected static final int EXTRA = 1;
    protected SpinnerAdapter adapter;
    protected Context context;
    protected int nothingSelectedLayout;
    protected int nothingSelectedDropdownLayout;
    protected LayoutInflater layoutInflater;

    /**
     * Use this constructor to have NO 'Select One...' item, instead use
     * the standard prompt or nothing at all.
     * @param spinnerAdapter wrapped Adapter.
     * @param nothingSelectedLayout layout for nothing selected, perhaps
     * you want text grayed out like a prompt...
     * @param context
     */
    public NothingSelectedSpinnerAdapter(
      SpinnerAdapter spinnerAdapter,
      int nothingSelectedLayout, Context context) {

        this(spinnerAdapter, nothingSelectedLayout, -1, context);
    }

    /**
     * Use this constructor to Define your 'Select One...' layout as the first
     * row in the returned choices.
     * If you do this, you probably don't want a prompt on your spinner or it'll
     * have two 'Select' rows.
     * @param spinnerAdapter wrapped Adapter. Should probably return false for isEnabled(0)
     * @param nothingSelectedLayout layout for nothing selected, perhaps you want
     * text grayed out like a prompt...
     * @param nothingSelectedDropdownLayout layout for your 'Select an Item...' in
     * the dropdown.
     * @param context
     */
    public NothingSelectedSpinnerAdapter(SpinnerAdapter spinnerAdapter,
            int nothingSelectedLayout, int nothingSelectedDropdownLayout, Context context) {
        this.adapter = spinnerAdapter;
        this.context = context;
        this.nothingSelectedLayout = nothingSelectedLayout;
        this.nothingSelectedDropdownLayout = nothingSelectedDropdownLayout;
        layoutInflater = LayoutInflater.from(context);
    }

    @Override
    public final View getView(int position, View convertView, ViewGroup parent) {
        // This provides the View for the Selected Item in the Spinner, not
        // the dropdown (unless dropdownView is not set).
        if (position == 0) {
            return getNothingSelectedView(parent);
        }
        return adapter.getView(position - EXTRA, null, parent); // Could re-use
                                                 // the convertView if possible.
    }

    /**
     * View to show in Spinner with Nothing Selected
     * Override this to do something dynamic... e.g. "37 Options Found"
     * @param parent
     * @return
     */
    protected View getNothingSelectedView(ViewGroup parent) {
        return layoutInflater.inflate(nothingSelectedLayout, parent, false);
    }

    @Override
    public View getDropDownView(int position, View convertView, ViewGroup parent) {
        // Android BUG! http://code.google.com/p/android/issues/detail?id=17128 -
        // Spinner does not support multiple view types
        if (position == 0) {
            return nothingSelectedDropdownLayout == -1 ?
              new View(context) :
              getNothingSelectedDropdownView(parent);
        }

        // Could re-use the convertView if possible, use setTag...
        return adapter.getDropDownView(position - EXTRA, null, parent);
    }

    /**
     * Override this to do something dynamic... For example, "Pick your favorite
     * of these 37".
     * @param parent
     * @return
     */
    protected View getNothingSelectedDropdownView(ViewGroup parent) {
        return layoutInflater.inflate(nothingSelectedDropdownLayout, parent, false);
    }

    @Override
    public int getCount() {
        int count = adapter.getCount();
        return count == 0 ? 0 : count + EXTRA;
    }

    @Override
    public Object getItem(int position) {
        return position == 0 ? null : adapter.getItem(position - EXTRA);
    }

    @Override
    public int getItemViewType(int position) {
        return 0;
    }

    @Override
    public int getViewTypeCount() {
        return 1;
    }

    @Override
    public long getItemId(int position) {
        return position >= EXTRA ? adapter.getItemId(position - EXTRA) : position - EXTRA;
    }

    @Override
    public boolean hasStableIds() {
        return adapter.hasStableIds();
    }

    @Override
    public boolean isEmpty() {
        return adapter.isEmpty();
    }

    @Override
    public void registerDataSetObserver(DataSetObserver observer) {
        adapter.registerDataSetObserver(observer);
    }

    @Override
    public void unregisterDataSetObserver(DataSetObserver observer) {
        adapter.unregisterDataSetObserver(observer);
    }

    @Override
    public boolean areAllItemsEnabled() {
        return false;
    }

    @Override
    public boolean isEnabled(int position) {
        return position != 0; // Don't allow the 'nothing selected'
                                             // item to be picked.
    }

}
aaronvargas
la source
52
Il s'agit d'une solution élégante au problème. Le code fonctionne exactement comme copié et copié dans mon projet. +1 pour aucune réflexion requise.
Richard Le Mesurier
2
C'est une excellente solution. Si quelqu'un veut savoir comment remplacer le titre non seulement avant qu'un élément ne soit sélectionné, mais à tout moment, dans l'appel getView (), renvoyez simplement getNothingSelectedView (ou toute autre vue personnalisée) à tout moment. La liste déroulante sera toujours remplie d'éléments de votre adaptateur, mais vous pouvez désormais contrôler le titre APRÈS que quelque chose soit également sélectionné.
OldSchool4664
6
C'est une solution vraiment élégante à un problème qui ne devrait pas exister (essayez le développement Iphone). Super et merci! Heureux que quelqu'un se souvienne des modèles, etc.
user1700737
3
@prashantwosti, le code a été mis à jour pour fonctionner avec Lollipop. Plus précisément getItemViewType () et getViewTypeCount ().
aaronvargas
3
@aaronvargas une fois sélectionné un élément du spinner, puis-je annuler et sélectionner "[Sélectionner une planète]"?
modabeckham
130

J'ai fini par utiliser un à la Buttonplace. Bien que a Buttonne soit pas a Spinner, le comportement est facile à personnaliser.

Créez d'abord l'adaptateur comme d'habitude:

String[] items = new String[] {"One", "Two", "Three"};
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
        android.R.layout.simple_spinner_dropdown_item, items);

Notez que j'utilise le simple_spinner_dropdown_itemcomme id de mise en page. Cela aidera à créer une meilleure apparence lors de la création de la boîte de dialogue d'alerte.

Dans le gestionnaire onClick de mon bouton, j'ai:

public void onClick(View w) {
  new AlertDialog.Builder(this)
  .setTitle("the prompt")
  .setAdapter(adapter, new DialogInterface.OnClickListener() {

    @Override
    public void onClick(DialogInterface dialog, int which) {

      // TODO: user specific action

      dialog.dismiss();
    }
  }).create().show();
}

Et c'est tout!

HRJ
la source
10
Je suis d'accord avec cette réponse. D'ailleurs, un bouton beaucoup plus facile à coiffer qu'un Spinner.
Romain Piel
@HRJ J'ai implémenté la façon dont vous l'avez suggéré, mais l'élément qui est sélectionné avant n'est pas mis en surbrillance (signifie que le bouton radio doit être mis en surbrillance avec un point vert au milieu) .... Comment puis-je obtenir cela dans la méthode OnClick () de bouton. S'il vous plaît, aidez-moi HRJ .....
Avadhani Y
2
Le bouton avec cette disposition est parfait <Button android: id = "@ + id / city" android: layout_width = "match_parent" android: layout_height = "wrap_content" android: layout_margin = "5dp" android: gravity = "left" android: background = "@ android: drawable / btn_dropdown" android: text = "@ string / city_prompt" />
kml_ckr
Comment mettriez-vous ensuite à jour le texte du bouton pour refléter la sélection, comme cela se passerait dans un spinner?
shim
3
solution du problème: juste au lieu de SetAdapter, utilisez SetSingleChoiceItems
Grzegorz Dev
67

Tout d'abord, vous pourriez être intéressé par l' promptattribut de la Spinnerclasse. Voir l'image ci-dessous, "Choisir une planète" est l'invite qui peut être définie dans le XML avec android:prompt="".

entrez la description de l'image ici

J'allais suggérer un sous Spinner- classement , où vous pourriez conserver deux adaptateurs en interne. Un adaptateur doté de l'option "Sélectionner un" et l'autre adaptateur réel (avec les options réelles), puis en utilisant le OnClickListenerpour changer les adaptateurs avant que la boîte de dialogue de choix ne s'affiche. Cependant, après avoir essayé de mettre en œuvre cette idée, je suis arrivé à la conclusion que vous ne pouvez pas recevoir d' OnClickévénements pour le widget lui-même.

Vous pouvez envelopper le spinner dans une vue différente, intercepter les clics sur la vue, puis demander à votre CustomSpinnercommutateur de changer d'adaptateur, mais cela semble être un horrible hack.

Avez-vous vraiment besoin de montrer "Select One"?

Casey
la source
36
Il ne s'agit pas seulement de devoir afficher "Select One", il traite également le cas où la valeur du spinner peut éventuellement être laissée vide.
greg7gkb
5
aussi, avec cette option, la Terre est affichée comme la sélection sur le Spinner avant que quoi que ce soit n'ait été choisi, pour mon application, je préfère que l'utilisateur soit en mesure de dire qu'il n'a encore rien choisi
dylan murphy
2
cela ne répond pas vraiment à la question. les gens recherchent un moyen pour que le spinner lui-même affiche par défaut "Select One" plutôt que le premier élément de la liste des planètes, dans cet exemple
JMRboosties
58

Ce code a été testé et fonctionne sur Android 4.4

entrez la description de l'image ici

Spinner spinner = (Spinner) activity.findViewById(R.id.spinner);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(activity, android.R.layout.simple_spinner_dropdown_item) {

            @Override
            public View getView(int position, View convertView, ViewGroup parent) {

                View v = super.getView(position, convertView, parent);
                if (position == getCount()) {
                    ((TextView)v.findViewById(android.R.id.text1)).setText("");
                    ((TextView)v.findViewById(android.R.id.text1)).setHint(getItem(getCount())); //"Hint to be displayed"
                }

                return v;
            }       

            @Override
            public int getCount() {
                return super.getCount()-1; // you dont display last item. It is used as hint.
            }

        };

        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        adapter.add("Daily");
        adapter.add("Two Days");
        adapter.add("Weekly");
        adapter.add("Monthly");
        adapter.add("Three Months");
        adapter.add("HINT_TEXT_HERE"); //This is the text that will be displayed as hint.


        spinner.setAdapter(adapter);
        spinner.setSelection(adapter.getCount()); //set the hint the default selection so it appears on launch.
        spinner.setOnItemSelectedListener(this);
Manos
la source
getItem(getCount())est souligné en rouge pour moi? Impossible de résoudre la méthode setHint
Zapnologica
J'ai un doute, vu de nombreuses solutions dans ce fil .. mais pourquoi tout le monde ajoute un indice au dernier. Est-ce mal d'ajouter un indice dans la première ligne?
akashPatra
Je ne peux pas définir 'setOnItemSelectedListener (this);' parce que j'utilise 'implements NavigationView.OnNavigationItemSelectedListener', puis-je supprimer 'setOnItemSelectedListener (this);' sans aucun problème?
CGR
@akashpatra La raison pour laquelle ils ajoutent un indice pour durer est que ArrayAdapter pour spinner peut obtenir ses valeurs de différentes sources au moment de l'exécution.
VinKrish
cela m'a vraiment aidé
sunil
31

J'ai trouvé cette solution:

String[] items = new String[] {"Select One", "Two", "Three"};
Spinner spinner = (Spinner) findViewById(R.id.mySpinner);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
            android.R.layout.simple_spinner_item, items);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);

spinner.setOnItemSelectedListener(new OnItemSelectedListener() {
    @Override
    public void onItemSelected(AdapterView<?> arg0, View arg1, int position, long id) {
        items[0] = "One";
        selectedItem = items[position];
    }

    @Override
    public void onNothingSelected(AdapterView<?> arg0) {
    }
});

Modifiez simplement le tableau [0] avec "Select One" puis dans onItemSelected, renommez-le en "One".

Pas une solution chic, mais ça marche: D

Marco da Gualdo
la source
5
Cela n'a pas fonctionné pour moi. Après avoir choisi l'élément "One", il est toujours dit "Select One".
Leo Landau
Cela ne fonctionnera pas car l'interface onItemSelected appellera toujours pour la première fois.
Vaibhav Kadam
20

Il n'y a pas d'API par défaut pour définir l'indice sur Spinner. Pour l'ajouter, nous avons besoin d'une petite solution de contournement sans mise en œuvre de la réflexion sur la sécurité

List<Object> objects = new ArrayList<Object>();
objects.add(firstItem);
objects.add(secondItem);
// add hint as last item
objects.add(hint);

HintAdapter adapter = new HintAdapter(context, objects, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);

Spinner spinnerFilmType = (Spinner) findViewById(R.id.spinner);
spinner.setAdapter(adapter);

// show hint
spinner.setSelection(adapter.getCount());

Source de l'adaptateur:

public class HintAdapter
        extends ArrayAdapter<Objects> {

    public HintAdapter(Context theContext, List<Object> objects) {
        super(theContext, android.R.id.text1, android.R.id.text1, objects);
    }

    public HintAdapter(Context theContext, List<Object> objects, int theLayoutResId) {
        super(theContext, theLayoutResId, android.R.id.text1, objects);
    }

    @Override
    public int getCount() {
        // don't display last item. It is used as hint.
        int count = super.getCount();
        return count > 0 ? count - 1 : count;
    }
}

Source primaire

Yakiv Mospan
la source
qu'est-ce que R.id.text1? s'agit-il d'une disposition ou d'une vue? veuillez élaborer votre réponse
Anand Savjani
Cela devrait êtreandroid.R.id.text1
Yakiv Mospan
J'ai un doute, vu de nombreuses solutions dans ce fil .. mais pourquoi tout le monde ajoute un indice au dernier. Est-ce mal d'ajouter un indice dans la première ligne?
akashPatra
@akashpatra Je ne me souviens pas exactement, mais il semble qu'il y ait eu un problème lorsque j'ai essayé d'en faire la première liste d'articles. Quoi qu'il en soit, vous pouvez toujours l'essayer et commenter ici, toute la magie est autour de la getCountméthode
Yakiv Mospan
@YakivMospan J'obtiens un NPE lorsque j'utilise ceci, probablement à cause de Reflection lors de l'utilisation de ProGuard. Savez-vous comment résoudre ce problème?
Alan
17

Beaucoup de réponses ici, mais je suis surpris que personne n'ait suggéré une solution simple: placez une TextView sur le Spinner. Définissez un écouteur de clic sur le TextView qui cache le TextView montre le Spinner et appelle spinner.performClick ().

mjancola
la source
9

J'ai eu le même problème pour spinner, avec une sélection vide, et j'ai trouvé une meilleure solution. Jetez un oeil à ce code simple.

Spinner lCreditOrDebit = (Spinner)lCardPayView.findViewById(R.id.CARD_TYPE);
spinneradapter lAdapter = 
  new spinneradapter(
    BillPayScreen.this, 
    ndroid.R.layout.simple_spinner_item,getResources().getStringArray(R.array.creditordebit));
lAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
lCreditOrDebit.setAdapter(lAdapter);

Ici, spinneradapter est une petite personnalisation pour arrayadapter. Cela ressemble à ceci:

import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;

public class spinneradapter extends ArrayAdapter<String>{
    private Context m_cContext;
    public spinneradapter(Context context,int textViewResourceId, String[] objects) {
        super(context, textViewResourceId, objects);
        this.m_cContext = context;
    }

    boolean firsttime = true;
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if(firsttime){
            firsttime = false;
            //Just return some empty view
            return new ImageView(m_cContext);
        }
        //Let the array adapter take care of it this time.
        return super.getView(position, convertView, parent);
    }
}
Rajasekhar
la source
6
Le problème avec cette approche est qu'elle sélectionne toujours le premier élément de la liste lorsque la liste apparaît. Parce que c'est déjà sélectionné, vous ne pouvez pas le toucher pour sélectionner - il agit comme si aucune sélection ne s'était produite.
jwadsack
7

Vous pouvez le changer en vue texte et utiliser ceci:

android:style="@android:style/Widget.DeviceDefault.Light.Spinner"

puis définissez la android:textpropriété.

Christian Vielma
la source
Fonctionne uniquement pour API 14 et supérieur.
Giulio Piancastelli
6

Fichier XML:

<Spinner android:id="@+id/locationSpinner"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:prompt="@string/select_location" />

Activité:

private Spinner featuresSelection;
private ArrayAdapter<CharSequence> featuresAdapter;
private List<CharSequence> featuresList;

onCreate:

featuresList = new ArrayList<CharSequence>();
featuresAdapter = new ArrayAdapter<CharSequence>(this,
  android.R.layout.simple_spinner_item, featuresList);
featuresAdapter.setDropDownViewResource(
  android.R.layout.simple_spinner_dropdown_item);
featuresSelection = ((Spinner) yourActivity.this
  .findViewById(R.id.locationSpinner));
featuresSelection.setAdapter(featuresAdapter);
featuresSelection.setOnItemSelectedListener(
  new MyOnItemSelectedListener());

Certaines fonctions (ajouter des choses à l'adaptateur par programme)>

featuresAdapter.add("some string");

Vous avez maintenant un spinner vide et vous pouvez écrire du code pour ne pas ouvrir la boîte de dialogue s'il est vide. Ou ils peuvent appuyer. Mais vous le remplissez également avec une fonction ou une autre liste pendant l'exécution.

trgraglia
la source
Pas besoin non plus de notifierDataSetChanged () car il doit être défini sur true par défaut.
trgraglia
4

J'ai essayé comme suit. Prenez un bouton et donnez-lui l'événement click. En changeant l'arrière-plan du bouton, il semble être un spinner.

Déclarez comme variables globales alertdialog et valeur par défaut.

AlertDialog d;
static int default_value = 0;
final Button btn = (Button) findViewById(R.id.button1);
btn .setOnClickListener(new View.OnClickListener() {

@Override
public void onClick(View v)
{
    //c.show();
    final CharSequence str[] = {"Android","Black Berry","Iphone"};
        AlertDialog.Builder builder =
          new AlertDialog.Builder(TestGalleryActivity.this).setSingleChoiceItems(
            str, default_value,new  DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int position)
            {
                Toast.makeText(TestGalleryActivity.this,
                               "" + position,
                               Toast.LENGTH_SHORT).show();
                default_value = position;
                btn.setText(str[position]);
                if(d.isShowing())
                    d.dismiss();
            }
        }).setTitle("Select Any");
        d = builder.create();
        d.show();
    }
});
Ramesh Akula
la source
4

C'est mon chemin:

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
Cabezas
la source
cela ouvre le spinner en position basse
SpyZip
3

Jetez un œil à l'application iosched pour une solution à usage général pour ajouter un élément en haut d'une liste. En particulier, si vous utilisez un CursorAdapter, regardez TracksAdapter.java qui étend cette définition pour fournir une méthode "setHasAllItem" et le code associé pour gérer le nombre de listes pour gérer l'élément supplémentaire en haut.

En utilisant l'adaptateur personnalisé, vous pouvez définir le texte sur "Sélectionner un" ou tout ce que vous voudrez que cet élément supérieur dise.

sport
la source
3

J'ai un spinner sur mon main.xml et son identifiant est @+id/spinner1

voici ce que j'écris dans ma fonction OnCreate:

spinner1 = (Spinner)this.findViewById(R.id.spinner1);
final String[] groupes = new String[] {"A", "B", "C", "D", "E", "F", "G", "H"};
ArrayAdapter<CharSequence> featuresAdapter = new ArrayAdapter<CharSequence>(this, android.R.layout.simple_spinner_item, new ArrayList<CharSequence>());
featuresAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner1.setAdapter(featuresAdapter);
for (String s : groupes) featuresAdapter.add(s);

spinner1.setOnItemSelectedListener(new OnItemSelectedListener() {
     public void onItemSelected(AdapterView<?> arg0, View arg1, int position, long id) {
         // Here go your instructions when the user chose something
         Toast.makeText(getBaseContext(), groupes[position], 0).show();
     }
     public void onNothingSelected(AdapterView<?> arg0) { }
});

Il n'a besoin d'aucune implémentation dans la classe.

Cyril
la source
3

J'ai trouvé de nombreuses bonnes solutions pour cela. la plupart fonctionne en ajoutant un élément à la fin de l'adaptateur et n'affiche pas le dernier élément dans la liste déroulante. Le gros problème pour moi était que la liste déroulante spinner commencera par le bas de la liste. Ainsi, l'utilisateur voit les derniers éléments au lieu des premiers éléments (en cas de nombreux éléments à afficher), après avoir touché la roulette pour la première fois.

J'ai donc mis l'élément de conseil au début de la liste. et masquez le premier élément dans la liste déroulante.

private void loadSpinner(){

    HintArrayAdapter hintAdapter = new HintArrayAdapter<String>(context, 0);

    hintAdapter.add("Hint to be displayed");
    hintAdapter.add("Item 1");
    hintAdapter.add("Item 2");
            .
            .
    hintAdapter.add("Item 30");

    spinner1.setAdapter(hintAdapter);

    //spinner1.setSelection(0); //display hint. Actually you can ignore it, because the default is already 0
    //spinner1.setSelection(0, false); //use this if don't want to onItemClick called for the hint

    spinner1.setOnItemSelectedListener(yourListener);
}

private class HintArrayAdapter<T> extends ArrayAdapter<T> {

    Context mContext;

    public HintArrayAdapter(Context context, int resource) {
        super(context, resource);
        this.mContext = context
    }

    @Override 
    public View getView(int position, View convertView, ViewGroup parent) {

        LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
        View view = inflater.inflate(android.R.layout.simple_spinner_item, parent, false);
        TextView texview = (TextView) view.findViewById(android.R.id.text1);

        if(position == 0) {
            texview.setText("");
            texview.setHint(getItem(position).toString()); //"Hint to be displayed"
        } else {
            texview.setText(getItem(position).toString());
        }

        return view;
    }

    @Override
    public View getDropDownView(int position, View convertView, ViewGroup parent) {

        LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
        View view;

        if(position == 0){
            view = inflater.inflate(R.layout.spinner_hint_list_item_layout, parent, false); // Hide first row
        } else {
            view = inflater.inflate(android.R.layout.simple_spinner_dropdown_item, parent, false);
            TextView texview = (TextView) view.findViewById(android.R.id.text1);
            texview.setText(getItem(position).toString());
        } 

        return view;
    }
}

définissez la disposition ci-dessous dans @Override getDropDownView () lorsque la position est 0, pour masquer la première ligne d'indication.

R.layout.spinner_hint_list_item_layout:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" >

</LinearLayout>
Alireza Sobhani
la source
3

De plus, il existe une astuce simple pour afficher les valeurs par défaut:

Vous pouvez ajouter une valeur par défaut dans votre liste, puis ajouter toute votre collection à l'aide list.addAll(yourCollection);

Exemple de code réalisable ici:

List<FuelName> fuelList = new ArrayList<FuelName>();
                    fuelList.add(new FuelName(0,"Select One"));
                    fuelList.addAll(response.body());
                    ArrayAdapter adapter = new ArrayAdapter<>(getActivity(), android.R.layout.simple_spinner_item, fuelList);
                    //fuelName.setPrompt("Select Fuel");
                    fuelName.setAdapter(adapter);

J'espère que cela récupérera votre complexité. Bon codage!

Majedur Rahaman
la source
2

Je pense que le moyen le plus simple consiste à créer un élément factice sur l'index 0 en disant "sélectionnez-en un", puis à enregistrer, vérifiez peut-être que la sélection n'est pas 0.

Tobias
la source
4
Qu'en est-il de la visualisation de la liste des articles? Vous voulez voir la position "sélectionner un" en haut? Ce n'est pas seulement une question d'épargne.
Krzysztof Wolny
@KrzysztofWolny Spinner affiche par défaut l'élément à la position 0
rds
2

Voici donc mon dernier exemple "all-in" pour un bouton-spinner

Dans activity_my_form.xml

    <Button
        android:id="@+id/btnSpinnerPlanets"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:gravity="left|center_vertical"
        android:singleLine="true"
        android:text="@string/selectAPlanet"
        android:textSize="10sp"
        android:background="@android:drawable/btn_dropdown">
    </Button>

Dans strings.xml

<string name="selectAPlanet">Select planet&#8230;</string>

<string-array name="planets__entries">
    <item>The Sun with a name very long so long long long long longThe Sun with a name very long so long long long long longThe Sun with a name very long so long long long long long</item>
    <item>Mercury</item>
    <item>Venus</item>
    <item>Earth</item>
    <item>Mars</item>
    <item>Jupiter</item>
    <item>Saturn</item>
    <item>Uranus</item>
    <item>Neptune</item>
</string-array>

Dans MyFormActivity.java

public class MyFormActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        ((Button) findViewById(R.id.btnSpinnerPlanets)).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                final String[] items = view.getResources().getStringArray(R.array.planets__entries);
                ArrayAdapter<String> adapter = new ArrayAdapter<String>(MyFormActivity.this, android.R.layout.simple_spinner_dropdown_item, items);
                new AlertDialog.Builder(MyFormActivity.this).setTitle("the prompt").setAdapter(adapter, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        ((Button) findViewById(R.id.btnSpinnerPlanets)).setText(items[which]);
                        dialog.dismiss();
                    }
                }).create().show();
            }
        });     

    }

}   

Enfin j'ai obtenu une taille de police configurable sans premier élément sélectionnable bouton spinner !!! Merci à HRJ

wildnove
la source
1

Lors de l'extension SpinnerAdapter, vous remplacez deux Viewméthodes de production, getView(int, View, ViewGroup)et getDropDownView(int, View, ViewGroup). Le premier fournit l' Viewinséré dans Spinnerlui - même; le second fournit le Viewdans la liste déroulante (comme son nom l'indique). Vous pouvez remplacer le getView(...)afin que, jusqu'à ce qu'un élément soit sélectionné, il affiche un TextViewcontenant une invite; puis, lorsque vous détectez qu'un élément a été sélectionné, vous le modifiez pour afficher un TextViewcorrespondant à cela.

public class PromptingAdapter extends SpinnerAdapter {

    //... various code ...

    private boolean selectionmade = false;

    //call this method from the OnItemSelectedListener for your Spinner
    public setSelectionState(boolean b) {
        selectionmade = b;
    }

    @Override
    public View getView(int position, View recycle, ViewGroup container) {
        if(selectionmade) {
            //your existing code to supply a View for the Spinner
            //you could even put "return getDropDownView(position, recycle, container);"
        }
        else {
            View output;
            if(recycle instanceof TextView) {
                 output = recycle;
            }
            else {
                 output = new TextView();
                 //and layout stuff
            }
            output.setText(R.string.please_select_one);
            //put a string "please_select_one" in res/values/strings.xml
            return output;
        }
    }

//...
}
Andrew Wyld
la source
1
J'ai découvert une faille dans cette méthode: le Spinner sélectionne automatiquement un élément immédiatement. Je trouverai un moyen de contourner cela sous peu.
Andrew Wyld
J'ai parlé trop tôt. Je n'ai cependant pas abandonné. Notez que selon le Spinnertutoriel (qui affiche soi-disant un ToastAPRÈS avoir sélectionné un élément) cet OUGHT fonctionne: developer.android.com/resources/tutorials/views/…
Andrew Wyld
1

Pour ceux qui utilisent Xamarin, voici l'équivalent C # de la réponse de aaronvargas ci-dessus.

using Android.Content;
using Android.Database;
using Android.Views;
using Android.Widget;
using Java.Lang;

namespace MyNamespace.Droid
{ 
  public class NothingSelectedSpinnerAdapter : BaseAdapter, ISpinnerAdapter, IListAdapter
  {
    protected static readonly int EXTRA = 1;
    protected ISpinnerAdapter adapter;
    protected Context context;
    protected int nothingSelectedLayout;
    protected int nothingSelectedDropdownLayout;
    protected LayoutInflater layoutInflater;

    public NothingSelectedSpinnerAdapter(ISpinnerAdapter spinnerAdapter, int nothingSelectedLayout, Context context) : this(spinnerAdapter, nothingSelectedLayout, -1, context)
    {
    }

    public NothingSelectedSpinnerAdapter(ISpinnerAdapter spinnerAdapter, int nothingSelectedLayout, int nothingSelectedDropdownLayout, Context context)
    {
      this.adapter = spinnerAdapter;
      this.context = context;
      this.nothingSelectedLayout = nothingSelectedLayout;
      this.nothingSelectedDropdownLayout = nothingSelectedDropdownLayout;
      layoutInflater = LayoutInflater.From(context);
    }

    protected View GetNothingSelectedView(ViewGroup parent)
    {
      return layoutInflater.Inflate(nothingSelectedLayout, parent, false);
    }

    protected View GetNothingSelectedDropdownView(ViewGroup parent)
    {
      return layoutInflater.Inflate(nothingSelectedDropdownLayout, parent, false);
    }

    public override Object GetItem(int position)
    {
      return position == 0 ? null : adapter.GetItem(position - EXTRA);
    }

    public override long GetItemId(int position)
    {
      return position >= EXTRA ? adapter.GetItemId(position - EXTRA) : position - EXTRA;
    }

    public override View GetView(int position, View convertView, ViewGroup parent)
    {
      // This provides the View for the Selected Item in the Spinner, not
      // the dropdown (unless dropdownView is not set).
      if (position == 0)
      {
        return GetNothingSelectedView(parent);
      }

      // Could re-use the convertView if possible.
      return this.adapter.GetView(position - EXTRA, null, parent);
    }

    public override int Count
    {
      get
      {
        int count = this.adapter.Count;
        return count == 0 ? 0 : count + EXTRA;
      }
    }

    public override View GetDropDownView(int position, View convertView, ViewGroup parent)
    {
      // Android BUG! http://code.google.com/p/android/issues/detail?id=17128 -
      // Spinner does not support multiple view types
      if (position == 0)
      {
        return nothingSelectedDropdownLayout == -1 ?
          new View(context) :
          GetNothingSelectedDropdownView(parent);
      }

      // Could re-use the convertView if possible, use setTag...
      return adapter.GetDropDownView(position - EXTRA, null, parent);
    }

    public override int GetItemViewType(int position)
    {
      return 0;
    }

    public override int ViewTypeCount => 1;

    public override bool HasStableIds => this.adapter.HasStableIds;

    public override bool IsEmpty => this.adapter.IsEmpty;

    public override void RegisterDataSetObserver(DataSetObserver observer)
    {
      adapter.RegisterDataSetObserver(observer);
    }

    public override void UnregisterDataSetObserver(DataSetObserver observer)
    {
      adapter.UnregisterDataSetObserver(observer);
    }

    public override bool AreAllItemsEnabled()
    {
      return false;
    }

    public override bool IsEnabled(int position)
    {
      return position > 0;
    }
  }
}
MPavlak
la source
1

J'ai également résolu ce problème en utilisant le code suivant. Supposons que vous ayez une liste d'articles, par exemple

ArrayList<Item> itemsArrayList = new ArrayList<Item>();
Item item1 = new Item();
item1.setId(1);
item1.setData("First Element");
Item item2 = new Item();
item2.setId(2);
Item2.setData("Second Element");
itemsArrayList.add(item1);
itemsArrayList.add(item2);

Maintenant, nous devons fournir les chaînes à spinner car spinner ne peut pas comprendre l'objet. Nous allons donc créer une nouvelle liste de tableaux avec des éléments de chaîne comme celui-ci ->

ArrayList<String> itemStringArrayList = new ArrayList<String>();
for(Item item : itemsArrayList) {
    itemStringArrayList.add(item.getData());
}

Nous avons maintenant une itemStringArrayListliste de tableaux avec deux éléments de chaîne. Et nous devons afficher le texte "Select Item" comme premier élément. Nous devons donc insérer une nouvelle chaîne dans le itemStringArrayList.

itemStringArrayList.add("Select Item");

Nous avons maintenant une liste de tableaux itemsArrayListet nous voulons afficher deux éléments dans la liste déroulante. Mais la condition ici est ... Si nous ne sélectionnons rien alorsSelect Item devrait apparaître comme premier élément qui ne sera pas activé.

Nous pouvons donc implémenter cette fonctionnalité comme ceci. Si vous devez charger les éléments de la liste de tableaux dans le spinner Android. Vous devrez donc utiliser un adaptateur. Alors ici, je vais utiliser le ArrayAdapter. Nous pouvons également utiliser l'adaptateur de personnalisation.

ArrayAdapter<String> itemsArrayAdapter = new ArrayAdapter<String>(getApplicationContext(), R.layout.spinner_item, itemsArrayList){
        @Override
        public boolean isEnabled(int position) {
            if(position == 0)
            {
                return false;
            }
            else
            {
                return true;
            }
        }

        @Override
        public View getDropDownView(int position, View convertView,
                                    ViewGroup parent) {
            View view = super.getDropDownView(position, convertView, parent);
            TextView tv = (TextView) view;
            if(position == 0){
                // Set the hint text color gray
                tv.setTextColor(Color.GRAY);
            }
            else {
                tv.setTextColor(Color.BLACK);
            }
            return view;
        }
    };

itemsArrayAdapter.setDropDownViewResource(R.layout.spinner_item);
your_spinner_name.setAdapter(itemsArrayAdapter);

Ici dans ce code. nous utilisons la disposition de spinner personnalisée, c'est-à-dire R.layout.spinner_item. C'est une simple vue texte

<?xml version="1.0" encoding="utf-8"?>
<TextView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="10dp"
    android:textStyle="italic"
    android:fontFamily="sans-serif-medium"
    />

Nous devons désactiver le premier texte dans le spinner. Donc, pour la position 0, nous désactivons le texte. Et nous pouvons également définir la couleur en remplaçant la méthode getDropDownView. Donc, de cette façon, nous obtiendrons le spinner attendu.

Shravan Jain
la source
0

Je voudrais juste utiliser un RadioGroup avec RadioButtons si vous n'avez que trois choix, vous pouvez les faire tous décochés au début.

stephane k.
la source
0

Aucune des réponses soumises précédemment n'a vraiment fonctionné comme je voulais résoudre ce problème. Pour moi, la solution idéale fournirait le "Select One" (ou tout autre texte initial) lorsque le spinner est affiché pour la première fois. Lorsque l'utilisateur appuie sur la double flèche, le texte initial ne doit pas faire partie de la liste déroulante qui s'affiche.

Pour compliquer davantage ma situation particulière, mes données de spinner viennent d'un curseur qui est chargé via les rappels LoaderManager.

Après une expérimentation considérable, j'ai trouvé la solution suivante:

public class MyFragment extends Fragment implements
LoaderManager.LoaderCallbacks<Cursor>{

private static final String SPINNER_INIT_VALUE = "Select A Widget";
private Spinner mSpinner;
private int mSpinnerPosition;
private boolean mSpinnerDropDownShowing = false;
private View mSpinnerDropDown;

private MyCursorAdapter mCursorAdapter;

...

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
...

mCursorAdapter = new MyCursorAdapter(getActivity());

mSpinner = (Spinner) rootView.findViewById(R.id.theSpinner);
mSpinner.setOnTouchListener(mSpinnerTouchListener);
mSpinner.setAdapter(mCursorAdapter);

...
}

//Capture the touch events to toggle the spinner's dropdown visibility
private OnTouchListener mSpinnerTouchListener = new View.OnTouchListener() {
    @Override
    public boolean onTouch(View view, MotionEvent motionEvent) {
        if(mSpinnerDropDown != null && mSpinnerDropDownShowing == false){
            mSpinnerDropDownShowing = true;
            mSpinnerDropDown.setVisibility(View.VISIBLE);
        }
        return false;
    }
};

//Capture the click event on the spinner drop down items
protected OnClickListener spinnerItemClick = new OnClickListener(){

    @Override
    public void onClick(View view) {
        String widget = ((TextView) view.findViewById(android.R.id.text1)).getText().toString();

        if(!widget.equals(SPINNER_INIT_VALUE)){
            if(mCursorAdapter != null){
                Cursor cursor = mCursorAdapter.getCursor();
                if(cursor.moveToFirst()){
                    while(!cursor.isAfterLast()){
                        if(widget.equals(cursor.getString(WidgetQuery.WIDGET_NAME))){

                            ...

                            //Set the spinner to the correct item
                            mSpinnerPosition = cursor.getPosition() + 1;
                            mSpinner.setSelection(mSpinnerPosition);
                            break;
                        }
                        cursor.moveToNext();
                    }
                }
            }
        }

        //Hide the drop down. Not the most elegent solution but it is the only way I could hide/dismiss the drop down
        mSpinnerDropDown = view.getRootView();
        mSpinnerDropDownShowing = false;
        mSpinnerDropDown.setVisibility(View.GONE);
    }
};

private class MyCursorAdapter extends CursorAdapter {

    private final int DISPLACEMENT = 1;
    private final int DEFAULT_ITEM_ID = Integer.MAX_VALUE;

    private Activity mActivity;

    public MyCursorAdapter(Activity activity) {
            super(activity, null, false);
            mActivity = activity;
    }

    //When loading the regular views, inject the defualt item
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if(position == 0){
            if(convertView == null){
                convertView = mActivity.getLayoutInflater().inflate(R.layout.list_item_widget, parent, false);
            }
            return getDefaultItem(convertView);
        }
        return super.getView(position - DISPLACEMENT, convertView, parent);
    }

    //When loading the drop down views, set the onClickListener for each view
    @Override
    public View getDropDownView(int position, View convertView, ViewGroup parent){
        View view = super.getDropDownView(position, convertView, parent);
        view.setOnClickListener(spinnerItemClick);
        return view;
    }

    //The special default item that is being injected
    private View getDefaultItem(View convertView){
        TextView text = (TextView) convertView.findViewById(android.R.id.text1);
        text.setText(SPINNER_INIT_VALUE);
        return convertView;
    }

    @Override
    public long getItemId(int position) {
        if (position == 0) {
            return DEFAULT_ITEM_ID;
        }
        return super.getItemId(position - DISPLACEMENT);
    }

    @Override
    public boolean isEnabled(int position) {
        return position == 0 ? true : super.isEnabled(position - DISPLACEMENT);
    }

    @Override
    public int getViewTypeCount() {
        return super.getViewTypeCount() + DISPLACEMENT;
    }

    @Override
    public int getItemViewType(int position) {
        if (position == 0) {
            return super.getViewTypeCount();
        }

        return super.getItemViewType(position - DISPLACEMENT);
    }

    @Override
    public View newView(Context context, Cursor cursor, ViewGroup parent) {
        return mActivity.getLayoutInflater().inflate(R.layout.list_item_widget, parent, false);
    }

    @Override
    public void bindView(View view, Context context, Cursor cursor){

        if(cursor.isAfterLast()){
            return;
        }

        TextView text = (TextView) view.findViewById(android.R.id.text1);
        String WidgetName = cursor.getString(WidgetQuery.WIDGET_NAME);
        text.setText(WidgetName);
    }
}
}
Jed
la source
0

Je gère cela en utilisant un bouton au lieu d'un Spinner. J'ai l'exemple de projet sur GitHub.

Dans le projet, j'affiche le Spinner et le bouton pour montrer qu'ils sont effectivement identiques. À l'exception du bouton, vous pouvez définir le texte initial comme vous le souhaitez.

Voici à quoi ressemble l'activité:

package com.stevebergamini.spinnerbutton;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Spinner;

public class MainActivity extends Activity {

    Spinner spinner1;
    Button button1;
    AlertDialog ad;
    String[] countries;

    int selected = -1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        spinner1 = (Spinner) findViewById(R.id.spinner1);
        button1 = (Button) findViewById(R.id.button1);

        countries = getResources().getStringArray(R.array.country_names);

        //  You can also use an adapter for the allert dialog if you'd like
        //  ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_dropdown_item, countries);        

        ad = new AlertDialog.Builder(MainActivity.this).setSingleChoiceItems(countries, selected,  
                new  DialogInterface.OnClickListener() {

                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            button1.setText(countries[which]);
                            selected = which;
                            ad.dismiss();

                        }}).setTitle(R.string.select_country).create(); 


        button1.setOnClickListener( new OnClickListener(){

            @Override
            public void onClick(View v) {
                ad.getListView().setSelection(selected);
                ad.show();              
            }});

    }

}

REMARQUE: Oui, je me rends compte que cela dépend du thème appliqué et l'apparence sera légèrement différente si vous utilisez Theme.Holo. Cependant, si vous utilisez l'un des thèmes hérités tels que Theme.Black, vous êtes prêt à partir.

SBerg413
la source
0

si vous rencontrez ce problème lorsque vos éléments sont remplis à partir du curseur de la base de données ,

la solution la plus simple que j'ai trouvée dans cette réponse SO:

utilisez UNION dans votre requête d'adaptateur de curseur et ajoutez l'élément supplémentaire avec id = -1 au résultat de la requête, sans vraiment l'ajouter à la base de données:

quelque chose comme:

db.rawQuery ("SELECT iWorkerId as _id, nvLastName as name FROM Worker w UNION SELECT -1 as _id, '' as name", null);

si l'élément sélectionné est -1, alors c'est la valeur par défaut. Sinon, c'est un enregistrement de la table.

dvrm
la source
0

Semble une solution banale, mais je mets généralement simplement un TextView à l'avant du spinner. L'ensemble du Xml ressemble à ceci. (hé les gars, ne me tirez pas dessus, je sais que certains d'entre vous n'aiment pas ce genre de mariage):

<FrameLayout
    android:id="@+id/selectTypesLinear"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal" >

    <Spinner
        android:id="@+id/spinnerExercises"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:entries="@array/exercise_spinner_entries"
        android:prompt="@string/exercise_spinner_prompt"
     />                         
    <TextView
        android:id="@+id/spinnerSelectText"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="Hey! Select this guy!"
        android:gravity="center"
        android:background="#FF000000" />


</FrameLayout>

Ensuite, je cache le TextView lorsqu'un élément a été sélectionné. De toute évidence, la couleur d'arrière-plan du TextView doit être la même que celle du Spinner. Fonctionne sur Android 4.0. Je ne sais pas sur les anciennes versions.

Oui. Parce que le Spinner appelle setOnItemSelectedListener au début, le masquage de la vue de texte peut être un peu délicat, mais peut être fait de cette façon:

    Boolean controlTouched;

    exerciseSpinner.setOnTouchListener(new OnTouchListener() {


        @Override
        public boolean onTouch(View v, MotionEvent event) {
            controlTouched = true; // I touched it but but not yet selected an Item.
            return false;
        }

    });
    exerciseSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {

        @Override
        public void onItemSelected(AdapterView<?> arg0, View arg1,
                int arg2, long arg3) {
            if (controlTouched) { // Are you sure that I touched it with my fingers and not someone else  ?
                spinnerSelText.setVisibility(View.GONE);
            }
        }

        @Override
        public void onNothingSelected(AdapterView<?> arg0) {
        }

    });
Claudio Ferraro
la source
0

pour moi, cela a fonctionné quelque chose comme ça. a l'amélioration qui ne modifie que le texte dans CERTAINES options, pas du tout.

Tout d'abord, je prends les noms du spinner et crée l'adaptateur de tableau avec une vue personnalisée, mais cela n'a plus d'importance maintenant, la clé remplace le getView et change à l'intérieur les valeurs que vous devez changer. Dans mon cas, c'était seulement le premier, le reste je laisse l'original

public void rellenarSpinnerCompeticiones(){
        spinnerArrayCompeticiones = new ArrayList<String>();
        for(Competicion c: ((Controlador)getApplication()).getCompeticiones()){
            spinnerArrayCompeticiones.add(c.getNombre());
        }
        //ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<String>(this,R.layout.spinner_item_competicion,spinnerArrayCompeticiones);
        ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<String>(this, R.layout.spinner_item_competicion, spinnerArrayCompeticiones){
            @Override
            public View getView(int position, View convertView, ViewGroup parent) {
                LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                final View v = vi.inflate(R.layout.spinner_item_competicion, null);
                final TextView t = (TextView)v.findViewById(R.id.tvCompeticion);
                if(spinnerCompeticion.getSelectedItemPosition()>0){
                    t.setText(spinnerArrayCompeticiones.get(spinnerCompeticion.getSelectedItemPosition()));
                }else{
                    t.setText("Competiciones");
                }
                return v;
            }
        };
        spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        spinnerCompeticion.setAdapter(spinnerArrayAdapter);
    }
Rako
la source
0

voici un simple

    private boolean isFirst = true;
private void setAdapter() {
    final ArrayList<String> spinnerArray = new ArrayList<String>();     
    spinnerArray.add("Select your option");
    spinnerArray.add("Option 1");
    spinnerArray.add("Option 2");
    spin.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> parentView, View selectedItemView, int position, long id) {
            TextView tv = (TextView)selectedItemView;
            String res = tv.getText().toString().trim();
            if (res.equals("Option 1")) {
            //do Something
        } else if (res.equals("Option 2")) {
            //do Something else
        }
        }

        @Override
        public void onNothingSelected(AdapterView<?> parentView) { }

    });

    ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.my_spinner_style,spinnerArray) {
         public View getView(int position, View convertView, ViewGroup parent) {
             View v = super.getView(position, convertView, parent);
             int height = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 25, getResources().getDisplayMetrics());                  
             ((TextView) v).setTypeface(tf2);
             ((TextView) v).getLayoutParams().height = height;
             ((TextView) v).setGravity(Gravity.CENTER);
             ((TextView) v).setTextSize(TypedValue.COMPLEX_UNIT_SP, 19);
             ((TextView) v).setTextColor(Color.WHITE);
             return v;
         }

         public View getDropDownView(int position, View convertView,
                 ViewGroup parent) {
             if (isFirst) {
                 isFirst = false;
                 spinnerArray.remove(0);
             }
             View v = super.getDropDownView(position, convertView, parent);                  
             ((TextView) v).setTextColor(Color.argb(255, 70, 70, 70));
             ((TextView) v).setTypeface(tf2);
             ((TextView) v).setGravity(Gravity.CENTER);
             return v;
         }
     };
     spin.setAdapter(adapter);
}
Sayka
la source
0

Reportez-vous à l'une des réponses ci-dessus: https://stackoverflow.com/a/23005376/1312796

J'ai ajouté mon code pour corriger un petit bug. Celui où aucune donnée n'a été récupérée .. Comment afficher le texte d'invite ..!

Voici mon astuce ... Cela fonctionne très bien avec moi. !

Essayez de placer votre spinner dans un Relative_layoutet alignez un Textview avec votre spinner et jouez avec la visibilité du Textview (SHOW / HIDE) chaque fois que l'adaptateur du spinner est chargé ou vide .. Comme ceci:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginTop="20dp"
android:background="#ededed"
android:orientation="vertical">



    <TextView
        android:id="@+id/txt_prompt_from"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:textColor="@color/gray"
        android:textSize="16sp"
        android:layout_alignStart="@+id/sp_from"
        android:text="From"
        android:visibility="gone"/>

    <Spinner
        android:id="@+id/sp_from"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        />

Voici le code:

  txt__from = (TextView) rootView.findViewById(R.id.txt_prompt_from);

appeler cette méthode après et avant que l'adaptateur de spinner soit chargé et vide.

setPromptTextViewVisibility (); //True or fales 

public void setPromptTextViewVisibility (boolean visible )
{
    if (visible)
    {
        txt_from.setVisibility(View.VISIBLE);
    }
    else
    {
        txt_from.setVisibility(View.INVISIBLE);
    }

}
Ibrahim AbdelGawad
la source