Wie erstelle ich einen Android Spinner mit dem Anfangstext "Select One"?

569

Ich möchte einen Spinner verwenden, der anfangs (wenn der Benutzer noch keine Auswahl getroffen hat) den Text "Select One" anzeigt. Wenn der Benutzer auf den Drehknopf klickt, wird die Liste der Elemente angezeigt und der Benutzer wählt eine der Optionen aus. Nachdem der Benutzer eine Auswahl getroffen hat, wird das ausgewählte Element im Spinner anstelle von "Select One" angezeigt.

Ich habe den folgenden Code, um einen Spinner zu erstellen:

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

Mit diesem Code wird zunächst der Punkt "Eins" angezeigt. Ich könnte einfach ein neues Element "Select One" zu den Elementen hinzufügen, aber dann würde "Select One" auch in der Dropdown-Liste als erstes Element angezeigt, was nicht das ist, was ich möchte.

Wie kann ich dieses Problem beheben?

Pieter Kuijpers
quelle
6
Die perfekte Lösung liegt in dieser Frage: stackoverflow.com/questions/9863378/… Überschreiben Sie einfach die Methode getDropDownView ().
Sourab Sharma
Haben Sie versucht, das erste Element Ihres Adapters auf "Select One" zu setzen?
Igor Ganapolsky
[Hier andere tolle nette Lösung!] [1] [1]: stackoverflow.com/questions/9863378/…
AirtonCarneiro
wiederverwendbarer Spinner: github.com/henrychuangtw/ReuseSpinner
HenryChuang

Antworten:

255

Hier ist eine allgemeine Lösung, die die SpinnerAnsicht überschreibt . Es überschreibt setAdapter(), um die Anfangsposition auf -1 zu setzen, und überträgt die angegebene SpinnerAdapterPosition, um die Eingabeaufforderungszeichenfolge für eine Position unter 0 anzuzeigen.

Dies wurde auf Android 1.5 bis 4.2 getestet, aber Käufer aufgepasst! Weil diese Lösung auf Reflexion beruht, um das private AdapterView.setNextSelectedPositionInt()und zu nennenAdapterView.setSelectedPositionInt() , es ist nicht garantiert , um Arbeit in Zukunft OS - Updates. Es scheint wahrscheinlich, dass es wird, aber es ist keineswegs garantiert.

Normalerweise würde ich so etwas nicht gutheißen, aber diese Frage wurde oft genug gestellt und es scheint eine vernünftige Anfrage zu sein, dass ich dachte, ich würde meine Lösung veröffentlichen.

/**
 * 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
quelle
7
@emmby Haben Sie eine Idee, wie Sie die Auswahl löschen können, nachdem der Benutzer sie festgelegt hat? Ich habe versucht, die beiden Aufrufe von invoke () in eine clearSelection () -Methode umzuwandeln, aber es funktioniert nicht wirklich. Obwohl in der Popup-Liste das zuvor ausgewählte Element als nicht ausgewählt angezeigt wird, wird es vom Drehfeld-Widget weiterhin als ausgewählt angezeigt. Wenn der Benutzer dasselbe Element erneut auswählt, wird onItemSelected () nicht aufgerufen.
Qwertie
3
könnten einige erklären, wie man über Klasse verwendet?
Bishan
4
Diese Lösung ist unter Android 4.2 (Cyanogenmod 10.1) mit Android: -Einträgen nicht 100% perfekt. Die Höhe der aufgeblasenen Textansicht ist kleiner als die Höhe der Ressource, die der Standardadapter aufbläst. Wenn Sie also tatsächlich eine Option auswählen, erhöht sich die Höhe um ~ 10 Pixel in meinem Galaxy S, was nicht akzeptabel ist. Ich habe verschiedene Dinge ausprobiert (Schwerkraft, Polsterung, Rand usw.) und keines hat zuverlässig auf allen Geräten funktioniert, daher werde ich mich für eine andere Lösung entscheiden.
Maragues
3
@DavidDoria Sie müssen die NoDefaultSpinner-Klasse in Ihrer Layoutdatei verwenden. Kopieren Sie die Quelle von oben in Ihr Projekt, z. B. in das Paket com.example.customviews. Verwenden Sie jetzt in Ihrer Layout-XML anstelle von <Spinner ...> <com.example.customviews.NoDefaultSpinner ...>. Der Rest des Codes kann gleich bleiben. Vergessen Sie nicht, das Attribut android: prompt zur Ansicht <com.example.customviews.NoDefaultSpinner> in Ihrem Layout hinzuzufügen.
Ridcully
2
@emmby spinnerBrand.setSelection (-1); funktioniert nicht
Sachin C
291

Was Sie tun können, ist, Ihre SpinnerAdapterAnsicht mit einer zu dekorieren, die zunächst die Ansicht "Auswahloption ..." enthält, damit der Spinner sie ohne Auswahl anzeigt.

Hier ist ein Arbeitsbeispiel, das für Android 2.3 und 4.0 getestet wurde (es verwendet nichts in der Kompatibilitätsbibliothek, daher sollte es für eine Weile in Ordnung sein). Da es sich um einen Dekorateur handelt, sollte es einfach sein, vorhandenen Code nachzurüsten, und es funktioniert auch gut mit CursorLoaders. (Cursor auf dem Wrap cursorAdapternatürlich tauschen ...)

Es gibt einen Android-Fehler, der die Wiederverwendung von Ansichten etwas erschwert. (Sie müssen also das setTagoder etwas anderes verwenden, um sicherzustellen, dass convertViewes korrekt ist.) Spinner unterstützt nicht mehrere Ansichtstypen

Code-Hinweise: 2 Konstruktoren

Auf diese Weise können Sie eine Standardaufforderung verwenden oder Ihr eigenes "Nichts ausgewählt" als erste Zeile oder beides oder keine definieren. (Hinweis: Einige Themen zeigen ein DropDown für einen Spinner anstelle eines Dialogfelds. Das Dropdown zeigt normalerweise nicht die Eingabeaufforderung an.)

Sie definieren ein Layout so, dass es wie eine Eingabeaufforderung aussieht, z. B. ausgegraut ...

Anfangs nichts ausgewählt

Verwenden einer Standardaufforderung (beachten Sie, dass nichts ausgewählt ist):

Mit einer Standardaufforderung

Oder mit einer Eingabeaufforderung und etwas Dynamischem (hätte auch keine Eingabeaufforderung haben können):

Eingabeaufforderung und nichts ausgewählte Zeile

Verwendung im obigen Beispiel

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
quelle
52
Dies ist eine elegante Lösung für das Problem. Code funktioniert genau so, wie er in mein Projekt kopiert und eingefügt wurde. +1 für keine Reflexion erforderlich.
Richard Le Mesurier
2
Dies ist eine großartige Lösung. Wenn jemand wissen möchte, wie der Titel nicht nur vor der Auswahl eines Elements, sondern jederzeit überschrieben werden kann, geben Sie im Aufruf getView () jederzeit getNothingSelectedView (oder eine andere benutzerdefinierte Ansicht) zurück. Die Dropdown-Liste wird weiterhin mit Elementen aus Ihrem Adapter gefüllt, aber Sie können jetzt den Titel steuern, nachdem auch etwas ausgewählt wurde.
OldSchool4664
6
Dies ist eine wirklich elegante Lösung für ein Problem, das nicht existieren sollte (versuchen Sie es mit der iPhone-Entwicklung). Großartig und danke!
Ich bin
3
@prashantwosti, der Code wurde aktualisiert, um mit Lollipop zu arbeiten. Insbesondere getItemViewType () und getViewTypeCount ().
Aaronargas
3
@aaronvargas Wenn ich einmal einen Gegenstand aus dem Spinner ausgewählt habe, kann ich ihn rückgängig machen und "[Planet auswählen]" auswählen?
Modabeckham
130

Ich habe Buttonstattdessen eine verwendet. Während a Buttonkein a ist Spinner, lässt sich das Verhalten leicht anpassen.

Erstellen Sie zuerst den Adapter wie gewohnt:

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

Beachten Sie, dass ich die simple_spinner_dropdown_itemals Layout-ID verwende. Auf diese Weise können Sie beim Erstellen des Warnungsdialogs ein besseres Erscheinungsbild erzielen.

Im onClick-Handler für meinen Button habe ich:

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

Und das ist es!

HRJ
quelle
10
Ich stimme dieser Antwort zu. Außerdem ist ein Knopf viel einfacher zu stylen als ein Spinner.
Romain Piel
@HRJ Ich habe die von Ihnen vorgeschlagene Methode implementiert, aber das zuvor ausgewählte Element wird nicht hervorgehoben (bedeutet, dass das Optionsfeld mit einem grünen Punkt in der Mitte hervorgehoben werden muss). Wie kann ich dies in der OnClick () -Methode von erreichen? Taste. Bitte helfen Sie mir HRJ .....
Avadhani Y
2
Die Schaltfläche mit diesem Layout ist perfekt <Button android: id = "@ + id / city" android: layout_width = "match_parent" android: layout_height = "wrap_content" android: layout_margin = "5dp" android :vity = "left" android: background = "@ android: drawable / btn_dropdown" android: text = "@ string / city_prompt" />
kml_ckr
Wie würden Sie dann den Text der Schaltfläche aktualisieren, um die Auswahl widerzuspiegeln, wie dies bei einem Spinner der Fall wäre?
Shim
3
Problemlösung: Verwenden Sie anstelle von SetAdapter SetSingleChoiceItems
Grzegorz Dev
67

Zunächst könnte Sie das promptAttribut der SpinnerKlasse interessieren . Siehe das Bild unten, "Choose a Planet" ist die Eingabeaufforderung, mit der im XML festgelegt werden kann android:prompt="".

Geben Sie hier die Bildbeschreibung ein

Ich wollte eine Unterklasse vorschlagen Spinner , in der Sie zwei Adapter intern warten können. Ein Adapter mit der Option "Select One" und der andere echte Adapter (mit den tatsächlichen Optionen) verwenden dann den OnClickListener, um die Adapter zu wechseln, bevor das Auswahldialogfeld angezeigt wird. Nachdem ich versucht habe, diese Idee umzusetzen, bin ich jedoch zu dem Schluss gekommen, dass Sie keine OnClickEreignisse für das Widget selbst empfangen können.

Sie könnten den Spinner in eine andere Ansicht einwickeln, die Klicks auf die Ansicht abfangen und dann Ihren CustomSpinnerAdapter wechseln, aber es scheint ein schrecklicher Hack zu sein.

Müssen Sie wirklich "Select One" anzeigen?

Casey
quelle
36
Es muss nicht nur "Select One" angezeigt werden, sondern es wird auch der Fall behandelt, in dem der Spinner-Wert optional leer gelassen werden kann.
Greg7gkb
5
Mit dieser Option wird die Erde auch als Auswahl auf dem Spinner angezeigt, bevor etwas ausgewählt wurde. Für meine App möchte ich dem Benutzer lieber mitteilen, dass er noch nichts ausgewählt hat
Dylan Murphy
2
Dies beantwortet die Frage nicht wirklich. Leute suchen nach einer Möglichkeit, den Spinner selbst standardmäßig "Select One" anstelle des ersten Elements in der Liste der Planeten
anzeigen zu lassen
58

Dieser Code wurde getestet und funktioniert unter Android 4.4

Geben Sie hier die Bildbeschreibung ein

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
quelle
getItem(getCount())ist für mich rot unterstrichen? Methode setHint
Zapnologica
Ich habe Zweifel, habe viele Lösungen in diesem Thread gesehen ... aber warum jeder dem letzten einen Hinweis hinzufügt. Ist es falsch, in der ersten Zeile einen Hinweis hinzuzufügen?
AkashPatra
Ich kann 'setOnItemSelectedListener (this)' nicht setzen. Kann ich 'setOnItemSelectedListener (this)' entfernen, weil ich 'implementiert NavigationView.OnNavigationItemSelectedListener' verwende? ohne Probleme?
CGR
@akashpatra Der Grund, warum sie den letzten Hinweis hinzufügen, ist, dass ArrayAdapter für Spinner seine Werte zur Laufzeit möglicherweise aus verschiedenen Quellen bezieht.
VinKrish
das hat mir wirklich geholfen
sunil
31

Ich habe diese Lösung gefunden:

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

Ändern Sie einfach das Array [0] mit "Select One" und benennen Sie es dann in onItemSelected in "One" um.

Keine klassische Lösung, aber es funktioniert: D.

Marco da Gualdo
quelle
5
Das hat bei mir nicht funktioniert. Nach Auswahl von Punkt "Eins" wird immer noch "Eins auswählen" angezeigt.
Leo Landau
Dies funktioniert nicht, da die onItemSelected-Schnittstelle immer zum ersten Mal aufgerufen wird.
Vaibhav Kadam
20

Es gibt keine Standard-API, um einen Hinweis auf Spinner festzulegen. Um es hinzuzufügen, benötigen wir eine kleine Problemumgehung ohne die Implementierung von Sicherheitsreflexionen

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

Adapterquelle:

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

Originalquelle

Yakiv Mospan
quelle
Was ist R.id.text1? Ist es ein Layout oder eine Ansicht? Bitte erläutern Sie Ihre Antwort
Anand Savjani
Es sollte seinandroid.R.id.text1
Yakiv Mospan
Ich habe Zweifel, habe viele Lösungen in diesem Thread gesehen ... aber warum jeder dem letzten einen Hinweis hinzufügt. Ist es falsch, in der ersten Zeile einen Hinweis hinzuzufügen?
AkashPatra
@akashpatra Ich erinnere mich nicht genau, aber anscheinend gab es ein Problem, als ich versuchte, es als erste Artikelliste zu erstellen. Wie auch immer, Sie können es immer versuchen und hier kommentieren, alle Magie hier ist um getCountMethode
Yakiv Mospan
@YakivMospan Ich bekomme eine NPE, wenn ich diese benutze, wahrscheinlich aufgrund von Reflection bei der Verwendung von ProGuard. Wissen Sie, wie Sie das beheben können?
Alan
17

Viele Antworten hier, aber ich bin überrascht, dass niemand eine einfache Lösung vorgeschlagen hat: Platzieren Sie eine Textansicht auf dem Spinner. Legen Sie in der Textansicht einen Klick-Listener fest, der die Textansicht verbirgt, die den Spinner anzeigt, und spinner.performClick () aufruft.

mjancola
quelle
9

Ich hatte das gleiche Problem für Spinner mit einer leeren Auswahl und fand eine bessere Lösung. Schauen Sie sich diesen einfachen Code an.

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

Hier ist Spinneradapter eine kleine Anpassung für Arrayadapter. Es sieht aus wie das:

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
quelle
6
Das Problem bei diesem Ansatz besteht darin, dass immer noch das erste Element in der Liste ausgewählt wird, wenn die Liste angezeigt wird. Da dies bereits ausgewählt ist, können Sie es nicht berühren, um es auszuwählen. Es verhält sich so, als ob keine Auswahl stattgefunden hat.
Jwadsack
7

Sie können es in eine Textansicht ändern und Folgendes verwenden:

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

und definieren Sie dann die android:textEigenschaft.

Christian Vielma
quelle
Funktioniert nur für API 14 und höher.
Giulio Piancastelli
6

XML-Datei:

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

Aktivität:

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

Einige Funktionen (Dinge programmgesteuert zum Adapter hinzufügen)>

featuresAdapter.add("some string");

Jetzt haben Sie einen leeren Spinner und können Code schreiben, um den Dialog nicht zu öffnen, wenn er leer ist. Oder sie können zurückdrücken. Sie füllen es aber auch zur Laufzeit mit einer Funktion oder einer anderen Liste.

trgraglia
quelle
Es ist auch nicht erforderlich ,DataSetChanged () zu benachrichtigen, da dies standardmäßig auf true festgelegt werden sollte.
Trgraglia
4

Ich habe wie folgt versucht. Nehmen Sie eine Schaltfläche und geben Sie das Klickereignis an. Durch Ändern des Schaltflächenhintergrunds scheint es sich um einen Spinner zu handeln.

Als globale Variablen deklarieren alertdialog und Standardwert.

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

Das ist mein Weg:

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
quelle
Dies öffnet den Spinner an der untersten Position
SpyZip
3

In der iosched-App finden Sie eine allgemeine Lösung zum Hinzufügen eines Elements zum Anfang einer Liste. Insbesondere wenn Sie einen Adapter Cursor verwenden, sehen Sie TracksAdapter.java , die diese Definition erstreckt sich ein „setHasAllItem“ Verfahren und eine zugehörigen Code , um die Liste Zahl , um mit dem zusätzlichen Elemente oben zu verwalten.

Mit dem benutzerdefinierten Adapter können Sie den Text auf "Select One" oder was auch immer Sie möchten, dass das oberste Element sagt.

Sport
quelle
3

Ich habe einen Spinner auf meiner main.xml und seine ID ist @+id/spinner1

Folgendes schreibe ich in meine OnCreate-Funktion:

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

Es braucht keine Implementierung in der Klasse.

Cyril
quelle
3

Ich habe dafür viele gute Lösungen gefunden. Die meisten arbeiten, indem sie ein Element am Ende des Adapters hinzufügen und nicht das letzte Element in der Dropdown-Liste anzeigen. Das große Problem für mich war, dass die Spinner-Dropdown-Liste am Ende der Liste beginnt. Der Benutzer sieht also die letzten Elemente anstelle der ersten Elemente (falls viele Elemente angezeigt werden müssen), nachdem er den Spinner zum ersten Mal berührt hat.

Also habe ich den Hinweis an den Anfang der Liste gesetzt. und verstecken Sie das erste Element in der Dropdown-Liste.

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

Legen Sie das folgende Layout in @Override getDropDownView () fest, wenn die Position 0 ist, um die erste Hinweiszeile auszublenden.

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

Darüber hinaus gibt es einen einfachen Trick, um die Standardeinstellung anzuzeigen:

Sie können Ihrer Liste einen Standardwert hinzufügen und dann Ihre gesamte Sammlung mit hinzufügen list.addAll(yourCollection);

Beispiel für einen funktionsfähigen Code hier:

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

Hoffe, es wird Ihre Komplexität wiederherstellen. Viel Spaß beim Codieren!

Majedur Rahaman
quelle
2

Ich denke, der einfachste Weg ist, ein Dummy-Element auf Index 0 zu erstellen, das "select one" sagt, und dann beim Speichern möglicherweise zu überprüfen, ob die Auswahl nicht 0 ist.

Tobias
quelle
4
Was ist mit dem Anzeigen der Liste der Elemente? Sie möchten die Position "Wählen Sie eine" oben sehen? Es geht nicht nur ums Sparen.
Krzysztof Wolny
@KrzysztofWolny Spinner zeigt standardmäßig das Element an Position 0
rds
2

Dies ist also mein letztes Beispiel "All-in" für einen Button-Spinner

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

    }

}   

Endlich habe ich eine konfigurierbare Schriftgröße erhalten, bei der kein erster Artikel ausgewählt werden kann !!! Vielen Dank an HRJ

Wildnove
quelle
1

Beim Erweitern SpinnerAdapterüberschreiben Sie zwei Viewproduzierende Methoden getView(int, View, ViewGroup)und getDropDownView(int, View, ViewGroup). Der erste liefert das Viewin sich Spinnerselbst eingefügte ; Die zweite enthält die Viewin der Dropdown-Liste (wie der Name schon sagt). Sie können das überschreiben, getView(...)sodass bis zur Auswahl eines Elements TextVieweine Eingabeaufforderung angezeigt wird. Wenn Sie dann feststellen, dass ein Element ausgewählt wurde, ändern Sie es so, dass ein TextViewentsprechendes Element angezeigt wird .

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
quelle
1
Ich habe einen Fehler bei dieser Methode entdeckt: Der Spinner wählt automatisch sofort einen Gegenstand aus. Ich werde in Kürze einen Weg finden, dies zu umgehen.
Andrew Wyld
Ich habe zu früh gesprochen. Ich habe jedoch nicht aufgegeben. Beachten Sie, dass nach demSpinner Tutorial (das angeblich ein ToastNACH der Auswahl eines Elements anzeigt ) dieses OUGHT funktionieren sollte: developer.android.com/resources/tutorials/views/…
Andrew Wyld
1

Für diejenigen, die Xamarin verwenden, ist hier das C #, das der obigen Antwort von aaronvargas entspricht.

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

Ich habe dieses Problem auch mit dem folgenden Code gelöst. Angenommen, Sie haben eine Liste von Elementen, z

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

Jetzt müssen wir die Zeichenfolgen für den Spinner bereitstellen, da der Spinner das Objekt nicht verstehen kann. Also werden wir eine neue Array-Liste mit String-Elementen wie diesem erstellen ->

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

Jetzt haben wir eine itemStringArrayListArray-Liste mit zwei String-Elementen. Und wir müssen den Text "Artikel auswählen" als ersten Artikel anzeigen. Also müssen wir einen neuen String in das einfügen itemStringArrayList.

itemStringArrayList.add("Select Item");

Jetzt haben wir eine Array-Liste itemsArrayList und möchten zwei Elemente in der Dropdown- anzeigen. Aber die Bedingung hier ist ... Wenn wir dann nichts auswählenSelect Item sollte es als erstes Element erscheinen, das nicht aktiviert wird.

So können wir diese Funktionalität so implementieren. Wenn Sie die Array-Listenelemente in den Android-Spinner laden müssen. Sie müssen also einen Adapter verwenden. Also hier werde ich die verwenden ArrayAdapter. Wir können auch den Anpassungsadapter verwenden.

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

Hier in diesem Code. Wir verwenden das angepasste Spinner-Layout, dh R.layout.spinner_item. Es ist eine einfache Textansicht

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

Wir müssen den ersten Text im Spinner deaktivieren. Für die Position 0 deaktivieren wir also den Text. Und Farbe können wir auch festlegen, indem wir die Methode getDropDownView überschreiben. Auf diese Weise erhalten wir den erwarteten Spinner.

Shravan Jain
quelle
0

Ich würde nur eine RadioGroup mit RadioButtons verwenden, wenn Sie nur drei Möglichkeiten haben, können Sie sie alle zunächst deaktivieren.

stephane k.
quelle
0

Keine der zuvor eingereichten Antworten funktionierte wirklich so, wie ich dieses Problem lösen wollte. Für mich würde die ideale Lösung das "Select One" (oder einen beliebigen Anfangstext) liefern, wenn der Spinner zum ersten Mal angezeigt wird. Wenn der Benutzer auf den Drehknopf tippt, sollte der ursprüngliche Text nicht Teil der angezeigten Dropdown-Liste sein.

Um meine spezielle Situation weiter zu verkomplizieren, kommen meine Spinnerdaten von einem Cursor, der über die LoaderManager-Rückrufe geladen wird.

Nach ausgiebigen Experimenten habe ich folgende Lösung gefunden:

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

Ich kümmere mich darum, indem ich einen Knopf anstelle eines Spinners benutze. Ich habe das Beispielprojekt auf GitHub.

Im Projekt zeige ich sowohl den Spinner als auch die Schaltfläche an, um zu zeigen, dass sie tatsächlich identisch aussehen. Mit Ausnahme der Schaltfläche können Sie den Anfangstext auf einen beliebigen Wert einstellen.

So sieht die Aktivität aus:

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

    }

}

HINWEIS: Ja, mir ist klar, dass dies vom angewendeten Thema abhängt und das Aussehen bei Verwendung von Theme.Holo geringfügig abweicht. Wenn Sie jedoch eines der älteren Themen wie Theme.Black verwenden, können Sie loslegen.

SBerg413
quelle
0

Wenn Sie mit diesem Problem konfrontiert sind, wenn Ihre Elemente vom Datenbankcursor ausgefüllt werden ,

Die einfachste Lösung, die ich in dieser SO-Antwort gefunden habe:

Verwenden Sie UNION in Ihrer Cursoradapterabfrage und fügen Sie das zusätzliche Element mit der ID = -1 zum Abfrageergebnis hinzu, ohne es wirklich zur Datenbank hinzuzufügen:

etwas wie:

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

Wenn das ausgewählte Element -1 ist, ist dies der Standardwert. Ansonsten ist es ein Datensatz aus der Tabelle.

dvrm
quelle
0

Scheint eine banale Lösung zu sein, aber normalerweise platziere ich einfach eine Textansicht vor dem Spinner. Die ganze XML sieht so aus. (Hey Leute, erschieß mich nicht, ich weiß, dass einige von euch diese Art von Ehe nicht mögen):

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

Dann verstecke ich die Textansicht, wenn ein Element ausgewählt wurde. Offensichtlich sollte die Hintergrundfarbe der Textansicht mit der des Spinners übereinstimmen. Funktioniert unter Android 4.0. Weiß nicht auf älteren Versionen.

Ja. Da der Spinner zu Beginn setOnItemSelectedListener aufruft, kann das Ausblenden der Textansicht etwas schwierig sein, kann aber folgendermaßen erfolgen:

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

bei mir hat es so ähnlich geklappt. hat die Verbesserung, dass nur der Text in einigen Optionen geändert wird, nicht in allen.

Zuerst nehme ich die Namen des Spinners und erstelle den Arrayadapter mit einer benutzerdefinierten Ansicht, aber es spielt jetzt keine Rolle, der Schlüssel überschreibt die getView und innerhalb ändert sich die Werte, die Sie ändern müssen. In meinem Fall war nur der erste, der Rest lasse ich das 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
quelle
0

Hier ist eine einfache

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

Lesen Sie eine der oben genannten Antworten: https://stackoverflow.com/a/23005376/1312796

Ich habe meinen Code hinzugefügt, um einen kleinen Fehler zu beheben. Dort wurden keine Daten abgerufen. Wie wird der Eingabeaufforderungstext angezeigt?

Hier ist mein Trick ... Es funktioniert gut mit mir. !

Versuchen Sie, Ihren Spinner in ein Relative_layout zu legen, eine Textansicht an Ihrem Spinner auszurichten und mit der Sichtbarkeit der Textansicht (SHOW / HIDE) zu spielen, wenn der Adapter des Spinners geladen oder leer ist.

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

Hier ist der Code:

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

Rufen Sie diese Methode nach und vor dem Laden und Leeren des Spinneradapters auf.

setPromptTextViewVisibility (); //True or fales 

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

}
Ibrahim AbdelGawad
quelle