Come realizzare uno Spinner Android con il testo iniziale "Seleziona uno"?


569

Voglio usare uno Spinner che inizialmente (quando l'utente non ha ancora effettuato una selezione) visualizza il testo "Seleziona uno". Quando l'utente fa clic sullo spinner, viene visualizzato l'elenco degli elementi e l'utente seleziona una delle opzioni. Dopo che l'utente ha effettuato una selezione, l'elemento selezionato viene visualizzato nello Spinner anziché in "Seleziona uno".

Ho il seguente codice per creare uno 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);

Con questo codice, inizialmente viene visualizzata la voce "Uno". Potrei semplicemente aggiungere un nuovo elemento "Seleziona uno" agli articoli, ma poi "Seleziona uno" verrebbe visualizzato anche nell'elenco a discesa come primo elemento, che non è quello che voglio.

Come posso risolvere questo problema?


6
Bugie soluzione perfetta in questa domanda: stackoverflow.com/questions/9863378/...~~V~~aux~~plural~~3rd Proprio sostituiscono il metodo getDropDownView ().
Sourab Sharma,

Hai provato a impostare il primo elemento dell'adattatore su "Seleziona uno"?
IgorGanapolsky,

[Qui altra soluzione bello grande!] [1] [1]: stackoverflow.com/questions/9863378/...
AirtonCarneiro


Risposte:


255

Ecco una soluzione generale che sovrascrive la Spinnervista. Esegue setAdapter()l' override per impostare la posizione iniziale su -1 e inoltra il proxy fornito SpinnerAdapterper visualizzare la stringa di prompt per la posizione inferiore a 0.

Questo è stato testato su Android da 1.5 a 4.2, ma fai attenzione! Poiché questa soluzione si basa sulla riflessione per chiamare il privato AdapterView.setNextSelectedPositionInt()e AdapterView.setSelectedPositionInt(), non è garantito che funzioni nei futuri aggiornamenti del sistema operativo. Sembra probabile che lo farà, ma non è affatto garantito.

Normalmente non perdonerei qualcosa del genere, ma questa domanda è stata posta abbastanza volte e sembra una richiesta abbastanza ragionevole che ho pensato di pubblicare la mia soluzione.

/**
 * 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);
        }
    }
}

7
@emmby Hai idea di come cancellare la selezione dopo che l'utente l'ha impostata? Ho provato a refactoring le due chiamate invoke () in un metodo clearSelection (), ma non funziona davvero. Sebbene l'elenco popup mostri l'elemento precedentemente selezionato come non selezionato, il widget Spinner lo mostra ancora come selezionato e se l'utente seleziona nuovamente lo stesso elemento, onItemSelected () non viene chiamato.
Qwertie,

3
qualcuno potrebbe spiegare come usare sopra la classe?
Bishan,

4
Questa soluzione non è perfetta al 100% su Android 4.2 (Cyanogenmod 10.1), utilizzando Android: voci. L'altezza di TextView gonfiato è inferiore all'altezza di qualsiasi risorsa gonfia l'adapter predefinito. Quindi, quando selezioni effettivamente un'opzione, l'altezza aumenta, ~ 10px nel mio Galaxy S, il che non è accettabile. Ho provato diverse cose (gravità, imbottitura, margine, ecc.) E nessuna ha funzionato in modo affidabile su tutti i dispositivi, quindi opterò per una soluzione diversa.
Maragues,

3
@DavidDoria Devi usare la classe NoDefaultSpinner nel tuo file di layout. Copia la fonte dall'alto nel tuo progetto, ad esempio nel pacchetto com.example.customviews. Ora nel tuo layout xml, invece di <Spinner ...> usa <com.example.customviews.NoDefaultSpinner ...> Il resto del codice può rimanere lo stesso. Non dimenticare di aggiungere l'attributo android: prompt alla vista <com.example.customviews.NoDefaultSpinner> nel layout.
Ridcully,

2
@emmby spinnerBrand.setSelection (-1); non funziona
Sachin C

291

Quello che puoi fare è decorare il tuo SpinnerAdaptercon uno che presenta una 'Seleziona opzione ...' Inizialmente per la visualizzazione dello Spinner con niente selezionato.

Ecco un esempio funzionante testato per Android 2.3 e 4.0 (non utilizza nulla nella libreria di compatibilità, quindi dovrebbe andare bene per un po ') Dato che è un decoratore, dovrebbe essere facile aggiornare il codice esistente e funziona bene anche con CursorLoaders. (Scambia il cursore sull'involucro cursorAdapterovviamente ...)

Esiste un bug Android che rende un po 'più difficile riutilizzare le visualizzazioni. (Quindi devi usare setTago qualcos'altro per assicurarti che convertViewsia corretto.) Spinner non supporta più tipi di vista

Note di codice: 2 costruttori

Ciò consente di utilizzare un prompt standard o di definire il proprio "niente selezionato" come prima riga, o entrambi o nessuno. (Nota: alcuni temi mostrano un DropDown per uno Spinner anziché una finestra di dialogo. Il menu a discesa normalmente non mostra il prompt)

Definisci un layout per "sembrare" come un prompt, ad esempio, disattivato ...

Iniziale niente selezionato

Utilizzando un prompt standard (notare che non è selezionato nulla):

Con un prompt standard

O con un prompt e qualcosa di dinamico (non avrebbe potuto avere anche un prompt):

Riga rapida e nulla selezionata

Utilizzo nell'esempio sopra

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.
    }

}

52
Questa è una soluzione elegante al problema. Il codice funziona esattamente come copia e copia nel mio progetto. +1 per nessuna riflessione richiesta.
Richard Le Mesurier,

2
Questa è un'ottima soluzione Se qualcuno vuole sapere come sovrascrivere il titolo non solo prima che un elemento sia selezionato, ma in ogni momento, nella chiamata getView (), restituisci getNothingSelectedView (o qualsiasi altra vista personalizzata) in qualsiasi momento. L'elenco a discesa verrà comunque popolato con elementi dall'adattatore, ma ora puoi controllare il titolo DOPO che è stato selezionato anche qualcosa.
OldSchool4664,

6
Questa è una soluzione davvero elegante a un problema che non dovrebbe esistere (prova lo sviluppo di Iphone). Ottimo e grazie! Sono contento che qualcuno abbia ricordato gli schemi ecc.
user1700737

3
@prashantwosti, il codice è stato aggiornato per funzionare con Lollipop. In particolare getItemViewType () e getViewTypeCount ().
Aaronvargas,

3
@aaronvargas una volta selezionato un oggetto dallo spinner posso annullare e selezionare "[Seleziona un pianeta]"?
Modabeckham,

130

Ho finito per usare un Buttoninvece. Mentre a Buttonnon è a Spinner, il comportamento è facile da personalizzare.

Innanzitutto crea l'adattatore come al solito:

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

Si noti che sto usando simple_spinner_dropdown_itemcome ID layout. Ciò contribuirà a creare un aspetto migliore durante la creazione della finestra di avviso.

Nel gestore onClick per il mio pulsante ho:

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();
}

E questo è tutto!


10
Sono d'accordo con quella risposta. Inoltre, un pulsante molto più facile da modellare di uno Spinner.
Romain Piel,

@HRJ Ho implementato il modo in cui hai suggerito, ma l'elemento che è stato selezionato prima non viene evidenziato (significa che il pulsante di opzione deve essere evidenziato con un punto verde nel mezzo) .... Come posso ottenere questo nel metodo OnClick () di pulsante. Per favore, aiutatemi HRJ .....
Avadhani Y

2
Il pulsante con questo layout è perfetto <Pulsante 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

Come aggiorneresti quindi il testo del pulsante per riflettere la selezione, come accadrebbe in uno spinner?
shim

3
soluzione del problema: proprio invece di SetAdapter usa SetSingleChoiceItems
Grzegorz Dev

67

Innanzitutto, potresti essere interessato promptall'attributo della Spinnerclasse. Vedi l'immagine sotto, "Scegli un pianeta" è il prompt che può essere impostato nell'XML con android:prompt="".

inserisci qui la descrizione dell'immagine

Stavo per suggerire una sottoclasse Spinner, dove potevi mantenere due adattatori internamente. Un adattatore che ha l'opzione "Seleziona uno" e l'altro adattatore reale (con le opzioni effettive), quindi utilizzare il OnClickListenerper cambiare gli adattatori prima che venga visualizzata la finestra di dialogo delle scelte. Tuttavia, dopo aver provato a implementare quell'idea sono giunto alla conclusione che non puoi ricevere OnClickeventi per il widget stesso.

Potresti avvolgere lo spinner in una vista diversa, intercettare i clic sulla vista e quindi dire a te CustomSpinnerdi cambiare l'adattatore, ma sembra un terribile hack.

Hai davvero bisogno di mostrare "Seleziona uno"?


36
Non è solo una questione di dover mostrare "Seleziona uno", ma risolve anche il caso in cui il valore del filatore può essere lasciato vuoto.
greg7gkb,

5
inoltre, con questa opzione, la Terra viene mostrata come la selezione sullo Spinner prima che sia stato scelto qualcosa, per la mia app preferirei che l'utente fosse in grado di dire che non aveva ancora scelto nulla
Dylan Murphy,

2
questo non risponde davvero alla domanda. le persone sono alla ricerca di un modo per far sì che lo spinner stesso mostri "Seleziona uno" anziché il primo elemento nell'elenco dei pianeti, in questo esempio
JMRboosties,

58

Questo codice è stato testato e funziona su Android 4.4

inserisci qui la descrizione dell'immagine

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);

getItem(getCount())è sottolineato in rosso per me? Impossibile risolvere il metodo set Suggerimento
Zapnologica

Ho un dubbio, ho visto molte soluzioni in questo thread ... ma perché tutti stanno aggiungendo un suggerimento all'ultimo. È sbagliato aggiungere un suggerimento nella prima riga?
AkashPatra,

Non riesco a impostare 'setOnItemSelectedListener (this);' perché sto usando 'implementa NavigationView.OnNavigationItemSelectedListener', posso rimuovere 'setOnItemSelectedListener (this);' senza problemi?
CGR,

@akashpatra Il motivo per cui aggiungono un suggerimento per ultimo è che ArrayAdapter per spinner potrebbe ottenere i suoi valori da diverse fonti in fase di esecuzione.
VinKrish,

questo mi ha davvero aiutato
sunil

31

Ho trovato questa soluzione:

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) {
    }
});

Basta cambiare l'array [0] con "Seleziona uno" e quindi in onItemSelected, rinominarlo in "Uno".

Non è una soluzione di classe, ma funziona: D


5
Questo non ha funzionato per me. Dopo aver scelto l'elemento "Uno", dice ancora "Seleziona uno".
Leo Landau,

Questo non funzionerà perché l'interfaccia onItemSelected chiamerà sempre per la prima volta.
Vaibhav Kadam,

20

Non esiste un'API predefinita per impostare un suggerimento su Spinner. Per aggiungerlo abbiamo bisogno di una piccola soluzione senza l'implementazione della riflessione sulla sicurezza

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());

Fonte dell'adattatore:

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;
    }
}

Fonte originale


che cos'è R.id.text1? è un layout o una vista? per favore elabora la tua risposta
Anand Savjani,

Dovrebbe essereandroid.R.id.text1
Yakiv Mospan il

Ho un dubbio, ho visto molte soluzioni in questo thread ... ma perché tutti stanno aggiungendo un suggerimento all'ultimo. È sbagliato aggiungere un suggerimento nella prima riga?
AkashPatra,

@akashpatra Non ricordo esattamente, ma sembra che ci sia stato qualche problema quando ho provato a farlo come primo elenco di articoli. Comunque puoi sempre provarlo e commentare qui, tutta la magia qui è intorno al getCountmetodo
Yakiv Mospan

@YakivMospan Ottengo un NPE quando lo uso, probabilmente a causa di Reflection quando utilizzo ProGuard. Sai come aggiustarlo?
Alan,

17

Molte risposte qui, ma sono sorpreso che nessuno abbia suggerito una soluzione semplice: posizionare un TextView sopra lo Spinner. Impostare un listener di clic su TextView che nasconde TextView mostra Spinner e chiama spinner.performClick ().


9

Ho avuto lo stesso problema con lo spinner, con una selezione vuota e ho trovato una soluzione migliore. Dai un'occhiata a questo semplice codice.

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);

Qui spinneradapter è una piccola personalizzazione per arrayadapter. Sembra così:

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);
    }
}

6
Il problema con questo approccio è che seleziona ancora il primo elemento nell'elenco quando viene visualizzato l'elenco. Poiché è già selezionato, non è possibile toccarlo per selezionare - si comporta come se non fosse mai stato selezionato.
jwadsack,

7

Puoi cambiarlo in una vista di testo e usare questo:

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

e quindi definire la android:textproprietà.


Funziona solo con API 14 e successive.
Giulio Piancastelli,

6

File XML:

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

Attività:

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());

Alcune funzioni (aggiungere elementi all'adattatore a livello di codice)>

featuresAdapter.add("some string");

Ora hai uno spinner vuoto e puoi scrivere codice per non aprire la finestra di dialogo se vuoto. Oppure possono premere indietro. Ma lo popoli anche con una funzione o un altro elenco durante il runtime.


Inoltre, non è necessario notificareDataSetChanged () poiché dovrebbe essere impostato su true per impostazione predefinita.
trgraglia,

4

Ho provato come il seguente. Prendi un pulsante e assegnagli l'evento click. Cambiando lo sfondo del pulsante, sembra essere un filatore.

Dichiarare come variabili globali alertdialog e valore predefinito.

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();
    }
});

4

Questo è il mio modo:

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

questo apre lo spinner nella posizione inferiore
SpyZip

3

Dai un'occhiata all'app iosched per una soluzione di uso generale per aggiungere un elemento in cima a un elenco. In particolare, se si utilizza un CursorAdapter, guardare TracksAdapter.java che estende tale definizione per fornire un metodo "setHasAllItem" e il codice associato per gestire il conteggio dell'elenco per gestire l'elemento aggiuntivo in alto.

Usando l'adattatore personalizzato puoi impostare il testo su "Seleziona uno" o qualsiasi altra cosa tu voglia dire quell'elemento in alto.


3

Ho uno spinner sul mio main.xml e il suo ID è @+id/spinner1

questo è ciò che scrivo nella mia funzione 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) { }
});

Non ha bisogno di alcuna implementazione nella classe.


3

Ho trovato molte buone soluzioni per questo. la maggior parte funziona aggiungendo un elemento alla fine dell'adattatore e non visualizza l'ultimo elemento nell'elenco a discesa. Il grosso problema per me è stato che l'elenco a discesa degli spinner inizierà dal fondo dell'elenco. Quindi l'utente vede gli ultimi elementi invece dei primi (nel caso in cui ci siano molti elementi da mostrare), dopo aver toccato il filatore per la prima volta.

Quindi ho inserito l'elemento di suggerimento all'inizio dell'elenco. e nascondi il primo elemento nell'elenco a discesa.

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;
    }
}

imposta il layout seguente in @Override getDropDownView () quando la posizione è 0, per nascondere la prima riga di suggerimento.

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>

3

Inoltre, c'è un semplice trucco per mostrare l'impostazione predefinita:

Puoi aggiungere un valore predefinito nel tuo elenco e quindi aggiungere tutta la tua raccolta utilizzando list.addAll(yourCollection);

Esempio di codice utilizzabile qui:

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);

Spero che recuperi la tua complessità. Buona programmazione!


2

Penso che il modo più semplice sia quello di creare un oggetto fittizio sull'indice 0 che dice "selezionane uno" e quindi al salvataggio magari controlla che la selezione non sia 0.


4
Che dire della visualizzazione dell'elenco di elementi? Vuoi vedere la posizione "seleziona una" in alto? Non è solo una questione di risparmio.
Krzysztof Wolny,

@KrzysztofWolny Spinner per impostazione predefinita visualizza l'elemento nella posizione 0
rds

2

Quindi questo è il mio ultimo esempio "all-in" per uno spinner di pulsanti

In 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>

In 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>

In 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();
            }
        });     

    }

}   

Finalmente ho ottenuto una dimensione del carattere configurabile senza la prima selezione di pulsanti selezionabili !!! Grazie a HRJ


1

Durante l'estensione SpinnerAdapter, si sostituiscono due Viewmetodi di produzione getView(int, View, ViewGroup)e getDropDownView(int, View, ViewGroup). Il primo fornisce l' Viewinserto in Spinnerse stesso; il secondo fornisce l' Viewelenco a discesa (come suggerisce il nome). È possibile sovrascrivere in getView(...)modo che, fino a quando un elemento è stato selezionato, visualizzi un messaggio TextViewcontenente un prompt; quindi, quando rilevi un elemento selezionato, lo cambi per visualizzarne uno TextViewcorrispondente.

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;
        }
    }

//...
}

1
Ho scoperto un difetto in questo metodo: lo Spinner seleziona automaticamente un oggetto immediatamente. Troverò un modo per aggirare questo a breve.
Andrew Wyld,

Ho parlato troppo presto. Non mi sono arreso, tuttavia. Si noti che secondo il Spinnertutorial (che presumibilmente mostra un ToastDOPO hai selezionato un oggetto) questo OUGHT per funzionare: developer.android.com/resources/tutorials/views/…
Andrew Wyld

1

Per coloro che usano Xamarin, ecco l'equivalente in C # della risposta di aaronvargas sopra.

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;
    }
  }
}

1

Ho anche risolto questo problema utilizzando il seguente codice. Supponiamo di avere un elenco di elementi, ad es

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);

Ora dobbiamo fornire le stringhe allo spinner perché lo spinner non può capire l'oggetto. Quindi creeremo un nuovo elenco di array con elementi stringa come questo ->

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

Ora abbiamo un itemStringArrayListelenco di array con due elementi stringa. E dobbiamo mostrare il testo "Seleziona elemento" come primo elemento. Quindi dobbiamo inserire una nuova stringa nel file itemStringArrayList.

itemStringArrayList.add("Select Item");

Ora abbiamo un elenco di array itemsArrayListe vogliamo mostrare due elementi nel menu a discesa. Ma la condizione qui è ... Se non selezioniamo nulla, Select Itemdovrebbe apparire come primo elemento che non sarà abilitato.

Quindi possiamo implementare questa funzionalità in questo modo. Se è necessario caricare gli elementi dell'elenco di array nello spinner Android. Quindi dovrai usare un adattatore. Quindi qui userò il ArrayAdapter. Possiamo usare anche l'adattatore di personalizzazione.

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);

Qui in questo codice. stiamo usando il layout del filatore personalizzato, ad es R.layout.spinner_item. È una semplice visualizzazione di testo

<?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"
    />

Dobbiamo disabilitare il primo testo nella casella di selezione. Quindi per la posizione 0 stiamo disabilitando il testo. E anche il colore può essere impostato sovrascrivendo il metodo getDropDownView. In questo modo otterremo il filatore previsto.


0

Userei un RadioGroup con RadioButtons se hai solo tre opzioni, puoi renderle tutte deselezionate all'inizio.


0

Nessuna delle risposte precedentemente inviate ha funzionato nel modo in cui volevo risolvere questo problema. Per me la soluzione ideale fornirebbe "Select One" (o qualunque testo iniziale) quando viene visualizzato per la prima volta lo spinner. Quando l'utente tocca lo spinner, il testo iniziale non dovrebbe far parte del menu a discesa visualizzato.

Per complicare ulteriormente la mia situazione particolare, i miei dati di spinner arrivano da un cursore che viene caricato tramite i callback di LoaderManager.

Dopo una considerevole sperimentazione, ho trovato la seguente soluzione:

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);
    }
}
}

0

Lo gestisco usando un pulsante anziché uno Spinner. Ho il progetto di esempio su GitHub.

Nel progetto, sto mostrando sia lo Spinner che il pulsante per mostrare che sembrano davvero identici. Tranne il pulsante è possibile impostare il testo iniziale come desiderato.

Ecco come si presenta l'attività:

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();              
            }});

    }

}

NOTA: Sì, mi rendo conto che questo dipende dal tema applicato e l'aspetto sarà leggermente diverso se si utilizza Theme.Holo. Tuttavia, se stai utilizzando uno dei temi legacy come Theme.Black, sei a posto.


0

se stai affrontando questo problema quando i tuoi articoli vengono popolati dal cursore del database ,

la soluzione più semplice che ho trovato in questa risposta SO:

utilizzare UNION nella query dell'adattatore del cursore e aggiungere l'elemento aggiuntivo con id = -1 al risultato della query, senza realmente aggiungerlo al DB:

qualcosa di simile a:

db.rawQuery ("SELEZIONA iWorkerId come _id, nvLastName come nome FROM Worker con UNION SELECT -1 come _id, '' come nome", null);

se l'elemento selezionato è -1, allora è il valore predefinito. Altrimenti è un record dalla tabella.


0

Sembra una soluzione banale ma di solito metto semplicemente un TextView nella parte anteriore dello spinner. L'intero Xml è simile a questo. (ehi ragazzi, non sparatemi, so che ad alcuni di voi non piace questo tipo di matrimonio):

<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>

Quindi nascondo TextView quando è stato selezionato un elemento. Ovviamente il colore di sfondo di TextView dovrebbe essere lo stesso di Spinner. Funziona su Android 4.0. Non so su versioni precedenti.

Sì. Poiché Spinner chiama setOnItemSelectedListener all'inizio, nascondere la visualizzazione del testo potrebbe essere un po 'complicato, ma può essere fatto in questo modo:

    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) {
        }

    });

0

per me ha funzionato in questo modo. ha il miglioramento che cambia solo il testo in ALCUNE opzioni, non in tutto.

Per prima cosa prendo i nomi dello spinner e creo l'arrayadapter con una vista personalizza, ma non importa adesso, la chiave ha la precedenza su getView e al suo interno cambia i valori che devi cambiare. Nel mio caso è stato solo il primo, il resto lascio l'originale

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);
    }

0

eccone uno semplice

    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);
}

0

Fare riferimento a una delle risposte di cui sopra: https://stackoverflow.com/a/23005376/1312796

Ho aggiunto il mio codice per correggere un piccolo bug. Quello in cui non sono stati recuperati dati .. Come mostrare il testo del prompt ..!

Ecco il mio trucco ... Funziona bene con me. !

Prova a mettere il tuo spinner in un Relative_layout e allinea un Textview con il tuo spinner e gioca con la visibilità del Textview (SHOW / HIDE) ogni volta che l'adattatore del filatore viene caricato o vuoto ...

<?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"
        />

Ecco il codice:

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

chiamare questo metodo dopo e prima dell'adattatore per spinner caricato e vuoto.

setPromptTextViewVisibility (); //True or fales 

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

}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.