2012-03-25 10 views
86

Sto cercando un modo per nascondere un elemento in un widget spinner Android. Ciò consentirebbe di simulare uno spinner senza elementi selezionati e garantisce che il callback onItemSelected() venga sempre chiamato per ogni elemento selezionato (se l'elemento nascosto è quello "corrente"). Normalmente nella trottola c'è sempre un oggetto che non genera una richiamata, cioè quella corrente.Come nascondere un elemento in uno spinner Android

C'è del codice su stackoverflow per come disabilitare (grigio) gli oggetti, ma non come nascondere gli elementi completamente come se non esistessero.

Dopo molte sperimentazioni ho trovato una soluzione un po 'hacker che funziona su varie vecchie e nuove piattaforme Android. Ha alcuni piccoli inconvenienti cosmetici che sono difficili da notare. Mi piacerebbe ancora sentire una soluzione più ufficiale, a parte "non farlo con uno spinner".

Nasconde sempre il primo elemento nella casella di selezione, ma potrebbe essere facilmente esteso per nascondere un elemento arbitrario o più di un elemento. Aggiungi un oggetto fittizio contenente una stringa vuota all'inizio del tuo elenco di oggetti spinner. Potresti voler impostare la selezione corrente dello spinner sulla voce 0 prima che si apra la finestra di dialogo dello spinner, questo simulerà uno spinner non selezionato.

esempio di installazione Spinner con metodo ArrayAdapter di override:

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

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

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

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

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

che cosa avete trovato sugli altri interwebs? Cosa hai provato fino ad ora? – dldnh

+0

@dldnh vedere la modifica. – Georgie

+0

Grazie per la soluzione, Georgie! – Yarovoy

risposta

0

Penso che sarà meglio mettere convalida sulla lista di array, piuttosto che su Spinner perché una volta che la voce è filtrata, sarà sicuro di aggiungere in Spinner

37

Per nascondere un elemento arbitrario o più di un elemento penso che sia possibile implementare il proprio adattatore e impostare l'indice (o l'elenco di array) dell'indice che si desidera nascondere.

public class CustomAdapter extends ArrayAdapter<String> { 

    private int hidingItemIndex; 

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

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

E utilizzare l'adattatore personalizzato quando si crea l'elenco di elementi.

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

int hidingItemIndex = 0; 

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

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

(non ho testato il codice) sperare che sia d'aiuto.

+0

Questa non è una soluzione. L'aggiornamento alla domanda fornisce il codice corretto. – dldnh

+10

Senza tv.setHeight (0), TextView è ancora visibile. – v4r

+0

ciao, ho usato questo codice per nascondere il primo oggetto nel mio spinner, sta funzionando bene, il mio spinner mi mostrerà il secondo oggetto, ma quando ho cliccato su quel secondo oggetto il testo su quell'oggetto sarà impostato sul mio spinner, non voglio mostrare alcun testo sul mio spinner quando ho cliccato su quell'elemento, per favore guidami? – Achin

15

È più semplice nascondere un elemento alla fine dell'elenco troncando l'elenco.

Ma è necessario selezionarlo prima in modo che compaia nella casella di selezione, quindi verificare se la selezione è stata modificata in una delle voci visualizzate.

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

Ero alla ricerca di mezz'ora cercando di trovare un approccio pulito, e questo è di gran lunga l'approccio migliore. Basta troncare la lista, ma l'oggetto esiste realmente. Eccellente. – KSdev

+1

Questo non sembra funzionare in Lollipop, il test [Select one] non compare inizialmente nello Spinner. Lo stesso codice su versioni precedenti di Android sembra fare ciò che tutti noi vogliamo. –

+1

Il testo dello spinner viene modificato in "String3" nella modifica dell'orientamento, anche lo spinner non viene modificato. @Romich – Vaikesh

1

Solo per interesse, ho fatto una soluzione per usare "Prompt" come suggerimento. Questo codice è fatto per Xamarin.Android, ma potrebbe essere perfettamente portato su Java in 10 minuti. Usalo come un semplice ArrayAdapter senza aggiungere elementi con indici indicizzati o conteggi all'indice. Imposta anche SpinnerGeolocation.SelectedItemId su -1 quando non viene selezionato nulla (hint è l'elemento corrente).

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

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

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

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

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

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

qualcuno può guardare nella mia [domanda] (http://stackoverflow.com/q/42438584/6854117)? – faisal1208

0

Ho trovato questa soluzione che ha risolto il mio problema.

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

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

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


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

     } 
    }); 
0

Un altro approccio che ha funzionato meglio per me è quello di restituire un nuovo oggetto vista vuota. Questo è decisamente un approccio pulito dato che non stai giocando con gli elementi dell'array.

Creare la classe di adattatori che si estende ArrayAdapter

all'interno del vostro metodo di

public View getView(int position, View convertView, ViewGroup parent) { 
    View row = getCustomView(); 
    if(position==0) // put the desired check here. 
     { 
      row = new View(context); 
     } 
    } 
    return row; 
} 
2

Per nascondere qualsiasi elemento nel menu a discesa filatore è necessario passare alla posizione di oggetto che deve nascose in base a criteri richiesti. ho raggiunto questo in un caso d'uso di nascondere l'elemento che viene selezionato dal menu a discesa

public class CustomAdapter extends ArrayAdapter<String> { 

private List<String> dates; 
private int hideItemPostion; 

public CustomAdapter (Context context, int resource, List<String> dates) { 
    super(context, resource,dates); 
    this.dates=dates; 
} 
public void setItemToHide(int itemToHide) 
{ 
    this.hideItemPostion =itemToHide; 
} 
@Override 
public View getDropDownView(int position, View convertView, ViewGroup parent) { 
    View v = null; 
    if (position == hideItemPostion) { 
     TextView tv = new TextView(getContext()); 
     tv.setVisibility(View.GONE); 
     tv.setHeight(0); 
     v = tv; 
     v.setVisibility(View.GONE); 
    } 
    else 
     v = super.getDropDownView(position, null, parent); 
    return v; 
}} 

e impostando l'adattatore è qualcosa di simile

final CustomAdapter dataAdapter = new CustomAdapter(this,R.layout.spinner_item,dates); 
    dataAdapter.setDropDownViewResource(R.layout.spinner_dropdown_item); 
    spinner.setAdapter(dataAdapter); 
    dataAdapter.setItemToHide(0); 

Selezionando alcune voci dal menu a discesa anche la posizione ha bisogno di cambiare

spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { 
     @Override 
     public void onItemSelected(AdapterView<?> adapterView, View view, final int i, long l) { 
     dataAdapter.notifyDataSetChanged(); 
      mEPGDateSelector.setSelection(i); 
      dataAdapter.setItemToHide(i);} 

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

     } 
    }); 
Problemi correlati