Android Spinner: Ruft das ausgewählte Elementänderungsereignis ab


407

Wie können Sie den Ereignis-Listener für einen Spinner einstellen, wenn sich das ausgewählte Element ändert?

Grundsätzlich versuche ich etwas Ähnliches zu tun:

spinner1.onSelectionChange = handleSelectionChange;

void handleSelectionChange(Object sender){
    //handle event
}

Ich habe diese Antworten ausprobiert, aber niemand war hilfreich. Sobald die Spinner-Komponente keine Elementklickereignisse mehr unterstützt. Spinner-Dokumentation

Antworten:


812

Einige der vorherigen Antworten sind nicht korrekt. Sie funktionieren für andere Widgets und Ansichten, aber in der Dokumentation für das Spinner-Widget heißt es eindeutig:

Ein Spinner unterstützt keine Item-Click-Ereignisse. Das Aufrufen dieser Methode löst eine Ausnahme aus.

Verwenden Sie stattdessen besser OnItemSelectedListener () :

spinner.setOnItemSelectedListener(new OnItemSelectedListener() {
    @Override
    public void onItemSelected(AdapterView<?> parentView, View selectedItemView, int position, long id) {
        // your code here
    }

    @Override
    public void onNothingSelected(AdapterView<?> parentView) {
        // your code here
    }

});

Das funktioniert bei mir.

Beachten Sie, dass die onItemSelected-Methode auch beim Erstellen der Ansicht aufgerufen wird, sodass Sie sie in den onCreate()Methodenaufruf einfügen können .


47
Das Problem dabei ist, dass die onItemSelected-Methode auch beim Erstellen der Ansicht aufgerufen wird. Der dort geschriebene Code wird also auch beim Start ausgeführt. Gibt es eine Möglichkeit, den enthaltenen Code nur auszuführen, wenn eine echte Elementauswahl vom Benutzer aufgerufen wird?
Kennethvr

39
Tatsächlich kann dieses Problem gelöst werden, indem der setOnItemSelectedListener in die OnStart-Methode zum Überschreiben und nicht in die onCreate-Methode eingefügt wird. dumm mich ...
Kennethvr

16
Ich habe den Listener in die onStart-Methode eingefügt, aber sie wird aufgerufen, bevor der Benutzer jemals etwas sehen kann, genau wie onCreate. In meinem Fall ist also eine Schaltfläche "Weiter" unsichtbar, bis der Benutzer etwas auswählt. Die Schaltfläche wird bei der ersten Anzeige sichtbar gemacht. Wollen Sie damit sagen, dass Ihre Erfahrung anders ist? Wenn ja, was machen Sie bei der fehlenden onStart-Methode anders?
Jewgeni Simkin

7
Verwenden Sie ein anderes Feld in Ihrem anonymen Listener, um die erste Auswahl aufzuzeichnen, und weisen Sie onItemSelected an, nichts zu tun, es sei denn, eine Auswahl wurde gefunden? Nur ein Gedanke.
Sam Svenbjorgchristiensensen

4
Was aber, wenn der Benutzer das "Standard" -Element auswählt, das oben steht? Dann onItemSelected(...)wird nicht getroffen. (Ich weiß, weil ich das gerade auf die harte Tour herausgefunden habe.)
Andrew Wyld

55
Spinner spnLocale = (Spinner)findViewById(R.id.spnLocale);

spnLocale.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
    public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) { 
        // Your code here
    } 

    public void onNothingSelected(AdapterView<?> adapterView) {
        return;
    } 
}); 

Hinweis: Denken Sie an eine Sache.

Das Spinner- OnItemSelectedListenerEvent wird zweimal ausgeführt:

  1. Spinner-Initialisierung
  2. Benutzer manuell ausgewählt

Versuchen Sie, diese beiden mithilfe der Flag-Variablen zu unterscheiden.


3
Meins wird auch zweimal angerufen! Ich kann nicht herausfinden, wie Sie zwischen den beiden unterscheiden?
MAC

18
Setzen Sie einfach einen globalen Booleschen Wert wie den Booleschen Wert initialDisplay = true; Und dann sehen Sie in Ihrem onSelect, ob es wahr ist und wenn ja, tun Sie nicht, was Sie sonst noch bei select tun würden, sondern setzen Sie das Flag auf false, wenn es das nächste Mal aufgerufen wird (wenn der Benutzer tatsächlich auswählt).
Jewgeni Simkin

Beste Erklärung zur Ausführung von OnclickListener.
Pankaj Kumar

6
Ich persönlich bin entsetzt darüber, dass etwas so Einfaches - ein so grundlegendes UI-Widget - so verdammt schwer zu implementieren ist ... im Ernst - wie schwer wäre es, eine Eigenschaft "Standardanzeigeelement" zu erstellen und die Eigenschaft "Boolesches Flag" in das Objekt zu integrieren Klasse selbst? Ich bin kein Fan von Objective C, aber ich werde sagen, dass die Implementierung von iOS-Widgets ungefähr 1/10 der Zeit in Android dauert.
Bennett Von Bennett

4
Ich stimme auch zu. Der Spinner ist ein vermasseltes Widget. Es ist sehr schwer zu wissen, wann das Popup oder Drop geöffnet oder geschlossen ist. Wäre es so schwer gewesen, ein Ereignis dafür hinzuzufügen? Die obige Lösung kann Ihnen FAST sagen, wann die Liste geöffnet oder geschlossen ist, hat jedoch drei Probleme: (1) Es gibt kein Ereignis zum Auswählen des bereits ausgewählten Elements (und die Liste wird geschlossen) und (2) Es gibt kein Ereignis zum Abbrechen (Berühren) off-list, um es zu schließen) und (3) onNothingSelected scheint nie für mich zu feuern.
Batdude

19

Sie können eine AdapterView.OnItemSelectedListenerKlasse in Ihrer Aktivität implementieren .

Und dann verwenden Sie die folgende Zeile innerhalb onCreate()

Spinner spin = (Spinner) findViewById(R.id.spinner);
spin.setOnItemSelectedListener(this);

Überschreiben Sie dann diese beiden Methoden:

public void onItemSelected(AdapterView<?> parent, View v, int position, long id) {
    selection.setText(items[position]);
}

public void onNothingSelected(AdapterView<?> parent) {
    selection.setText("");
}

16

https://stackoverflow.com/q/1714426/811625

Sie können vermeiden, dass OnItemSelectedListener () mit einer einfachen Prüfung aufgerufen wird: Speichern Sie den aktuellen Auswahlindex in einer Ganzzahlvariablen und prüfen Sie ihn in onItemSelected (..), bevor Sie etwas unternehmen.

Z.B:

Spinner spnLocale;

spnLocale = (Spinner)findViewById(R.id.spnLocale);

int iCurrentSelection = spnLocale.getSelectedItemPosition();

spnLocale.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
    public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) { 
    if (iCurrentSelection != i){
            // Your code here
    }
    iCurrentSelection = i;
    } 

    public void onNothingSelected(AdapterView<?> adapterView) {
        return;
    } 
}); 

Natürlich iCurrentSelectionsollte das im Objektbereich sein, damit dies funktioniert!


1
Sie können keine nicht endgültige Variable innerhalb einer anonymen inneren Klasse verwenden. Wenn die iCurrentSelectionVariable innerhalb dieser anonymen Klasse deklariert ist, funktioniert sie einwandfrei. Sie können es auf -1 initialisieren, damit der Code beim ersten Aufruf ausgeführt wird.
Dahvyd

2
@dahvyd war korrekt, wenn Sie dies verwenden, muss das int endgültig sein. Auf jeden Fall funktioniert es wirklich gut. Ich habe ein EditText-Feld deaktiviert, wenn Position 0 nicht ausgewählt war und wenn es geändert wurde, aktivieren Sie es erneut. Danke dafür.
Natur3

8

Suchen Sie Ihren Spinnernamen und Ihre ID und implementieren Sie diese Methode.

spinnername.setOnItemSelectedListener(new OnItemSelectedListener() {

    @Override
    public void onItemSelected(AdapterView<?> parentView, View selectedItemView, int position, long id) {
        // your code here
    }

    @Override
    public void onNothingSelected(AdapterView<?> parentView) {
        // your code here
    }
});

8

Es spielt keine Rolle, ob Sie OnItemSelectedListener in onCreate oder onStart festlegen - es wird weiterhin während der Erstellung oder des Starts der Aktivität aufgerufen.
Also können wir es in onCreate einstellen (und NICHT in onStart!).
Fügen Sie einfach ein Flag hinzu, um die erste Initialisierung herauszufinden:

private Spinner mSpinner;
private boolean mSpinnerInitialized;

dann in onCreate (oder onCreateView) einfach:

mSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
                if (!mSpinnerInitialized) {
                    mSpinnerInitialized = true;
                    return;
                }

                // do stuff
            }

            public void onNothingSelected(AdapterView<?> adapterView) {
                return;
            }
        });

1
Vielen Dank, dass Sie diese Flagge verwenden.
Javan R.

7

In den Dokumenten für das Spinner-Widget heißt es

Ein Spinner unterstützt keine Item-Click-Ereignisse.

Sie sollten verwenden setOnItemSelectedListener, um Ihr Problem zu behandeln.


6
spinner1.setOnItemSelectedListener(
    new AdapterView.OnItemSelectedListener() {
        //add some code here
    }
);

1
Dies behebt nicht das Problem, dass dieser Rückruf beim ersten Start des Spinners aufgerufen wird (wodurch eine Antwort ausgelöst wird, die nichts mit einem tatsächlich ausgewählten Element zu tun hat).
Jewgeni Simkin

4

Nehmen Sie eine globale Variable für die aktuelle Auswahl des Spinners:

int currentItem = 0;

spinner_counter = (Spinner)findViewById(R.id.spinner_counter);
String[] value={"20","40","60","80","100","All"};
aa=new ArrayAdapter<String>(this,R.layout.spinner_item_profile,value);
aa.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner_counter.setAdapter(aa);

spinner_counter.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
            if(currentItem == position){
                return; //do nothing
            }
            else
            {
                 TextView spinner_item_text = (TextView) view;
                 //write your code here
            }
            currentItem = position;
        }

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

        }
    });

//R.layout.spinner_item_profile
<?xml version="1.0" encoding="utf-8"?>

<TextView  android:id="@+id/spinner_item_text"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" 
android:layout_height="wrap_content"
android:background="@drawable/border_close_profile"
android:gravity="start"  
android:textColor="@color/black"         
android:paddingLeft="5dip"
android:paddingStart="5dip"
android:paddingTop="12dip"
android:paddingBottom="12dip"
/>

//drawable/border_close_profile
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
  <item>
   <shape android:shape="rectangle">
    <solid android:color="#e2e3d7" />
   </shape>
 </item>
<item android:left="1dp"
android:right="1dp"
android:top="1dp"
android:bottom="1dp">
<shape android:shape="rectangle">
    <solid android:color="@color/white_text" />
</shape>
</item>
</layer-list>

4

Wenn Sie einen echten onChangedListener () wollen. Speichern Sie den Anfangswert im Handler und prüfen Sie, ob er sich geändert hat. Es ist einfach und erfordert keine globale Variable. Funktioniert, wenn Sie mehr als einen Spinner auf der Seite haben.

String initialValue = // get from Database or your object
mySpinner.setOnItemSelectedListener(new SpinnerSelectedListener(initialValue));

...

protected class SpinnerSelectedListener implements AdapterView.OnItemSelectedListener {

        private SpinnerSelectedListener() {
            super();
        }

        public SpinnerSelectedListener(String initialValue) {
            this();
            this.initialValue = initialValue;
        }

        private String initialValue;

        // getter and setter removed.  

        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
            final String newValue = (String) spinHeight.getItemAtPosition(position);
            if (newValue.equals(initialValue) == false) {
               // Add your code here.  The spinner has changed value. 

               // Maybe useful.   
               // initialValue = newValue;
            }

        }

        @Override
        public void onNothingSelected(AdapterView<?> parent) {
               // Maybe useful.   
               // initialValue = null; 
        }
    }

Objekte sind dein Freund, benutze sie.


3
spinner.setOnItemSelectedListener(
            new AdapterView.OnItemSelectedListener() {

                @Override
                public void onItemSelected(AdapterView<?> arg0, View arg1,
                        int arg2, long arg3) {

                    // TODO Auto-generated method stub
                }

                @Override
                public void onNothingSelected(AdapterView<?> arg0) {
                    // TODO Auto-generated method stub

                }
                //add some code here
            }
        );

1

Dies funktioniert, initialisiert den Spinner und findviewbyid und verwendet dies, es wird funktionieren

    Spinner schemeStatusSpinner;

  schemeStatusSpinner = (Spinner) dialog.findViewById(R.id.spinner);

schemeStatusSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> parentView, View selectedItemView, int position, long id) {
            // your code here
            if(schemeStatusSpinner.getSelectedItemId()==4){
                reasonll.setVisibility(View.VISIBLE);
            }
            else {
                reasonll.setVisibility(View.GONE);
            }
        }

        @Override
        public void onNothingSelected(AdapterView<?> parentView) {
            // your code here
        }

    });

1

Der beste Weg , was ich denke , wäre ein haben , flagitemselected = 0;in onCreate(). Und auf dem ausgewählten Elementelement erhöhen Sie dieses Flag, dh flagitemselected++; und dann überprüfen

if(flagitemselected!=1)
{
// do your work here
}

Das wird mir wohl helfen.


0

Ein Trick, den ich gefunden habe, war das Einfügen Ihrer setOnItemSelectedListeners in onWindowFocusChanged anstelle von onCreate. Ich habe noch keine schlimmen Nebenwirkungen auf diese Weise gefunden. Richten Sie die Listener grundsätzlich ein, nachdem das Fenster gezeichnet wurde. Ich bin nicht sicher, wie oft onWindowFocusChanged ausgeführt wird, aber es ist einfach genug, sich eine Sperrvariable zu erstellen, wenn Sie feststellen, dass sie zu oft ausgeführt wird.

Ich denke, Android verwendet möglicherweise ein nachrichtenbasiertes Verarbeitungssystem. Wenn Sie alles in onCreate einfügen, kann es vorkommen, dass der Spinner nach dem Zeichnen gefüllt wird. Ihr Listener wird also ausgelöst, nachdem Sie den Speicherort festgelegt haben. Dies ist natürlich eine fundierte Vermutung, aber Sie können mich gerne korrigieren.


0

Standardmäßig erhalten Sie das erste Element des Spinner-Arrays durch

value = spinner.getSelectedItem().toString();

Wenn Sie den Wert im Drehfeld ausgewählt haben, erhalten Sie den ausgewählten Wert

Wenn Sie die Position des ausgewählten Elements möchten, machen Sie es so

pos = spinner.getSelectedItemPosition();

Die beiden oben genannten Antworten gelten ohne Anwendung des Hörers

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.