So verstecken Sie ein Element in einem Android Spinner

101

Ich suche nach einer Möglichkeit, ein Element in einem Android-Spinner-Widget auszublenden. Auf diese Weise können Sie einen Spinner ohne ausgewählte Elemente simulieren und sicherstellen, dass der Rückruf onItemSelected () immer für jedes ausgewählte Element aufgerufen wird (wenn das versteckte Element das "aktuelle" ist). Normalerweise befindet sich im Spinner immer ein Element, das keinen Rückruf generiert, nämlich das aktuelle.

Der Stapelüberlauf enthält Code zum Deaktivieren (Ausgrauen) von Elementen, jedoch nicht zum vollständigen Ausblenden von Elementen, als ob sie nicht vorhanden wären.

Nach langem Experimentieren habe ich eine etwas hackige Lösung gefunden, die auf verschiedenen alten und neuen Android-Plattformen funktioniert. Es hat einige kleinere kosmetische Nachteile, die schwer zu bemerken sind. Ich würde immer noch gerne von einer offizielleren Lösung hören, außer "Mach das nicht mit einem Spinner".

Dies verbirgt immer den ersten Gegenstand im Spinner, kann aber ziemlich leicht erweitert werden, um einen beliebigen Gegenstand oder mehr als einen Gegenstand auszublenden. Fügen Sie am Anfang Ihrer Liste der Spinner-Elemente ein Dummy-Element mit einer leeren Zeichenfolge hinzu. Möglicherweise möchten Sie die aktuelle Spinnerauswahl auf Element 0 setzen, bevor das Spinnerdialogfeld geöffnet wird. Dadurch wird ein nicht ausgewählter Spinner simuliert.

Beispiel für die Einrichtung eines Spinners mit Überschreibung der ArrayAdapter-Methode:

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);
Georgie
quelle
Was haben Sie in den anderen Interwebs gefunden? Was hast du bisher versucht?
dldnh
Sorry lah, ich weiß nicht wie ich es machen soll.
Louisth
Schöne Lösung! Aber ich denke, die tv.setVisibility(View.GONE);Linie ist unnötig. Das Auskommentieren scheint keinen (visuellen) Unterschied zu machen, zumindest unter Android 4.4.2 / KitKit (auf einem LG / Google Nexus 4).
Matthias
Die Antwort in dieser Frage funktioniert gut ..
Rat-a-tat-a-tat Ratatouille
Dies ist möglicherweise keine Verbesserung, aber ich habe setTag(1)die Textansicht an Position 0 verwendet und dann convertView.getTag() != nullfestgestellt, ob die wiederverwendete Ansicht die für Position 0 erstellte Ansicht mit der Höhe 0 oder eine normale Ansicht für andere Spinnerelemente war. Dies war so, dass ich super.getDropDownView(position, convertView, parent)manchmal verwenden konnte, anstatt immer eine neue Ansicht zu erstellen.
Daniel Handojo

Antworten:

49

Um ein beliebiges Element oder mehr als ein Element auszublenden, können Sie meines Erachtens Ihren eigenen Adapter implementieren und den Index (oder die Array-Liste der Indizes) festlegen, den Sie ausblenden möchten.

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

Verwenden Sie Ihren benutzerdefinierten Adapter, wenn Sie die Liste der Elemente erstellen.

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

(Ich habe den Code nicht getestet) hoffe, das hilft.

Aebsubis
quelle
1
Dies ist keine Lösung. Das Update der Frage liefert den richtigen Code.
dldnh
13
Ohne tv.setHeight (0) ist die Textansicht weiterhin sichtbar.
v4r
Hallo, ich habe diesen Code verwendet, um das erste Element in meinem Spinner auszublenden. Es funktioniert einwandfrei. Mein Spinner zeigt mir das zweite Element an. Wenn ich jedoch auf dieses zweite Element geklickt habe, wird der Text auf diesem Element auf meinen Spinner gesetzt Ich möchte keinen Text auf meinem Spinner anzeigen, wenn ich auf diesen Artikel geklickt habe. Bitte führe mich.
Achin
1
Genial :) Einfache Lösung :)
Chaitanya
1
Klappt wunderbar..!
Krupa Kakkad
20

Es ist einfacher, ein Element am Ende der Liste auszublenden, indem Sie die Liste abschneiden.

Sie müssen es jedoch zuerst auswählen, damit es im Drehfeld angezeigt wird, und dann prüfen, ob die Auswahl in eines der angezeigten Elemente geändert wurde.

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
Romich
quelle
3
Ich habe eine halbe Stunde lang versucht, einen sauberen Ansatz zu finden, und dies ist bei weitem der beste Ansatz. Schneiden Sie einfach die Liste ab, aber das Element ist tatsächlich vorhanden. Ausgezeichnet.
KSdev
1
Dies scheint in Lollipop nicht zu funktionieren, der [Select one] -Test wird zunächst nicht im Spinner angezeigt. Der gleiche Code auf älteren Android-Versionen scheint das zu tun, was wir alle wollen.
Jonathan Caryl
1
Der Spinner-Text wird bei einer Änderung der Ausrichtung in 'String3' geändert, auch wenn der Spinner unberührt bleibt. @ Romich
Yksh
Kann jemand meine Frage untersuchen ?
Moeez
5

Um einen Gegenstand in der Spinner-Dropdown-Liste auszublenden, müssen Sie die Position des Gegenstands übergeben, der anhand der erforderlichen Kriterien ausgeblendet werden muss. Ich habe dies in einem Anwendungsfall erreicht, in dem das aus der Dropdown-Liste ausgewählte Element ausgeblendet wurde

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

Das Einstellen des Adapters ist ungefähr so

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

Bei Auswahl einiger Elemente aus der Dropdown-Liste muss auch die Position geändert werden

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

        }
    });
Jiju Induchoodan
quelle
1

Nur aus Interesse habe ich eine Lösung gefunden, um "Eingabeaufforderung" als Hinweis zu verwenden. Dieser Code ist wie gemacht Xamarin.Android, kann aber in 10 Minuten perfekt auf Java portiert werden. Verwenden Sie es wie ein einfaches ArrayAdapterElement, ohne dem Quellarray Elemente mit 0 oder Zählindex hinzuzufügen. Es wird auch SpinnerGeolocation.SelectedItemIdauf -1 gesetzt , wenn nichts ausgewählt ist ( hintist das aktuelle Element).

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;
        }
    }
}
KD
quelle
Kann jemand meine Frage untersuchen ?
Moeez
1

Ich habe diese Lösung gefunden, die mein Problem gelöst hat.

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;

       }
    });
Abdul Vajid
quelle
0

Ich denke, es ist besser, die Validierung auf die Array-Liste zu setzen, als auf Spinner, da es sicher ist, Spinner hinzuzufügen, sobald das Element gefiltert ist

Akhilesh
quelle
0

Ein anderer Ansatz, der für mich am besten funktioniert hat, ist die Rückgabe eines neuen leeren Ansichtsobjekts. Dies ist ein sehr sauberer Ansatz, da Sie nicht mit Array-Elementen spielen.

Erstellen Sie Ihre Adapterklasse als Erweiterung ArrayAdapter

innerhalb Ihrer Methode

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;
}
jeet.chanchawat
quelle
0

Dies ist eine sehr alte Frage, aber ich habe einen schönen (und wahrscheinlich) sauberen Weg gefunden, um auch nicht die ersten Elemente anzuzeigen. Inspiriert von @ Romichs Antwort habe ich eine ähnliche Logik hinzugefügt, um die ersten Elemente zu überspringen.

Dadurch wird eine beliebige Anzahl von Elementen effektiv ausgeblendet (standardmäßig 1). Der Code gibt nur an, dass die Größe der zu rendernden Objekte kürzer ist als sie tatsächlich ist, und ändert auch den Index der zu rendernden Elemente, sodass eine beliebige Anzahl von Elementen übersprungen wird.

Um die Dinge einfach zu halten, habe ich eine Lösung ausgeschlossen, die ich derzeit verwende und die das Ausblenden einer Liste zufälliger Elemente unterstützt, die jedoch durch wenige Änderungen am Code problemlos verwaltet werden kann.

class ArrayAdapterCustom(context: Context, textViewResourceId: Int, vararg objects: String)
    : ArrayAdapter<String>(context, textViewResourceId, objects) {

    //Can skip first n items (skip 1 as default)
    var hideFirstItemsCount = 1

    override fun getCount(): Int {
        return super.getCount() - hideFirstItemsCount
    }

    override fun getDropDownView(position: Int, convertView: View?, parent: ViewGroup): View {
        return super.getDropDownView(position + hideFirstItemsCount, convertView, parent)
    }
}
Muhamed Avdić
quelle