Android Spinner: pobierz wybrane zdarzenie zmiany przedmiotu


407

Jak ustawić detektor zdarzeń dla pokrętła, gdy zmienia się wybrany element?

Zasadniczo próbuję zrobić coś podobnego do tego:

spinner1.onSelectionChange = handleSelectionChange;

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

Próbowałem tych odpowiedzi, ale nikt nie był pomocny. Gdy składnik Spinnera nie obsługuje zdarzeń kliknięcia przedmiotu. Dokumentacja Spinnera

Odpowiedzi:


812

Niektóre z poprzednich odpowiedzi są nieprawidłowe. Działają w przypadku innych widżetów i widoków, ale dokumentacja widżetu Spinner wyraźnie stwierdza:

Błystka nie obsługuje zdarzeń kliknięcia przedmiotu. Wywołanie tej metody spowoduje wyjątek.

Lepiej użyj zamiast tego 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
    }

});

To działa dla mnie.

Zauważ, że metoda onItemSelected jest również wywoływana podczas budowania widoku, więc możesz rozważyć umieszczenie go w onCreate()wywołaniu metody.


47
Problem polega na tym, że metoda onItemSelected jest również wywoływana podczas budowania widoku. Tak więc kod, który jest tam zapisany, jest również uruchamiany podczas uruchamiania. Czy istnieje sposób wykonania zawierającego kod tylko wtedy, gdy użytkownik wywołuje prawdziwy wybór przedmiotów?
Kennethvr

39
w rzeczywistości problem ten można rozwiązać, umieszczając setOnItemSelectedListener w zastępującej metodzie OnStart, a nie w metodzie onCreate. głupi ja ...
Kennethvr

16
Umieściłem detektor w metodzie onStart, ale jest on wywoływany, zanim użytkownik zobaczy cokolwiek, tak jak onCreate, więc w moim przypadku przycisk „kontynuuj”, który ma być niewidoczny, dopóki użytkownik nie wybierze czegoś, przycisk jest widoczny przy pierwszym wyświetleniu. Mówisz, że twoje doświadczenie jest inne? Jeśli tak, to co robisz inaczej w metodzie onStart, której mi brakuje?
Jewgienij Simkin

7
Użyj innego pola w swoim anonimowym detektorze, aby zapisać pierwszy wybór i powiedz onItemSelected, aby nic nie robił, chyba że napotkasz wybór? Tylko myśl.
Sam Svenbjorgchristiensensen

4
Ale co, jeśli użytkownik wybierze element „domyślny”, ten na górze? Wtedy onItemSelected(...)nie jest trafiony. (Wiem, bo właśnie dowiedziałem się tego na
własnej skórze

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

Uwaga: pamiętaj o jednej rzeczy.

OnItemSelectedListenerEvent Spinner zostanie wykonany dwukrotnie:

  1. Inicjalizacja pokrętła
  2. Użytkownik wybrany ręcznie

Spróbuj rozróżnić te dwa, używając zmiennej flag.


3
Mój dzwoni też dwukrotnie! Nie mogę zrozumieć, jak je rozróżniasz?
MAC

18
Wystarczy ustawić globalną wartość logiczną, jak Boolean initialDisplay = true; A potem w swoim onSelect sprawdź, czy to prawda, a jeśli tak, nie rób niczego, co zamierzałeś zrobić na select, ale ustaw flagę na false, do następnego wywołania (kiedy użytkownik faktycznie wybierze).
Jewgienij Simkin

Najlepsze wyjaśnienie dotyczące wykonania OnclickListener.
Pankaj Kumar

6
Osobiście jestem przerażony, że coś tak prostego - tak podstawowy widget interfejsu użytkownika - jest tak cholernie trudne do wdrożenia ... poważnie - jak trudno byłoby zbudować właściwość „domyślnie wyświetlanego elementu” i wbudować właściwość flagi logicznej w obiekt sama klasa? Nie jestem fanem Objective C, ale powiem, że implementacja widgetu iOS zajmuje około 1/10 czasu w porównaniu z Androidem.
Bennett Von Bennett

4
Również się zgadzam. Spinner to jeden zepsuty widget. Bardzo trudno jest wiedzieć, kiedy wyskakujące okienko lub upuszczenie jest otwarte lub zamknięte. Czy tak trudno byłoby dodać do tego wydarzenie? Powyższe rozwiązanie może PRAWIE powiedzieć, kiedy lista jest otwarta lub zamknięta, ale ma trzy problemy: (1) nie ma zdarzenia do wybrania już wybranego elementu (a lista zamyka się) i (2) nie ma zdarzenia do przerwania (dotknij poza listą, aby go zamknąć) i (3) onNothingSelected nigdy nie wydaje mi się strzelać.
Batdude

19

Możesz zaimplementować AdapterView.OnItemSelectedListenerzajęcia w swojej działalności.

A następnie użyj poniższej linii onCreate()

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

Następnie zastąp te dwie metody:

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

Można uniknąć wywołania OnItemSelectedListener () za pomocą prostego sprawdzenia: Zachowaj bieżący indeks wyboru w zmiennej całkowitej i sprawdź w onItemSelected (..) zanim cokolwiek zrobisz.

Na przykład:

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

Przyczyna iCurrentSelectionpowinna być w zakresie obiektowym, aby to działało!


1
Nie można użyć nieokreślonej zmiennej w anonimowej klasie wewnętrznej. Jeśli iCurrentSelectionzmienna zostanie zadeklarowana w tej anonimowej klasie, będzie działać dobrze. Możesz zainicjować go na -1, aby kod był wykonywany przy pierwszym wywołaniu.
dahvyd

2
@dahvyd miał rację, jeśli użyjesz tego, int musi być ostateczny. W każdym razie działa naprawdę dobrze. Wyłączałem pole EditText, jeśli pozycja 0 nie została wybrana i jeśli się zmieniła, włącz ją ponownie. Dzięki za to.
natur3

8

Znajdź nazwę przędzarki i znajdź identyfikator, a następnie zastosuj tę metodę.

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

Nie ma znaczenia, czy ustawisz OnItemSelectedListener w onCreate czy onStart - będzie on nadal wywoływany podczas tworzenia lub uruchamiania działania (odpowiednio).
Możemy więc ustawić go w onCreate (a NIE w onStart!).
Wystarczy dodać flagę, aby wymyślić pierwszą inicjalizację:

private Spinner mSpinner;
private boolean mSpinnerInitialized;

następnie w onCreate (lub onCreateView) wystarczy:

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
Dziękujemy za skorzystanie z tej flagi.
Javan R.

7

Dokumenty dotyczące widżetu typu spinner mówią

Błystka nie obsługuje zdarzeń kliknięcia przedmiotu.

Powinieneś użyć, setOnItemSelectedListeneraby poradzić sobie z problemem.


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

1
Nie rozwiązuje to problemu wywołania tego wywołania zwrotnego podczas pierwszego uruchomienia pokrętła (wywołując w ten sposób odpowiedź, która nie ma nic wspólnego z faktycznie wybranym przedmiotem).
Jewgienij Simkin

4

weź zmienną globalną dla bieżącego wyboru pokrętła:

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

Jeśli chcesz true onChangedListener (). Zapisz wartość początkową w module obsługi i sprawdź, czy uległa zmianie. Jest prosty i nie wymaga zmiennej globalnej. Działa, jeśli na stronie znajduje się więcej niż jedna przędzarka.

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

Przedmioty są twoim przyjacielem, używaj ich.


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

To zadziała, zainicjalizuj pokrętło i znajdź viewbyid i użyj tego, to zadziała

    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

Najlepszym sposobem, co myślę, że byłoby mieć flagitemselected = 0;in onCreate(). I na wybranej pozycji zdarzeń przyrostu że flagi IE flagitemselected++; a następnie sprawdź

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

To chyba pomoże.


0

Jedną sztuczką, którą znalazłem, było umieszczenie twoich setOnItemSelectedListeners w onWindowFocusChanged zamiast onCreate. Nie znalazłem jeszcze żadnych złych skutków ubocznych, aby robić to w ten sposób. Zasadniczo skonfiguruj detektory po narysowaniu okna. Nie jestem pewien, jak często działa onWindowFocusChanged, ale łatwo jest stworzyć sobie zmienną blokującą, jeśli okaże się, że działa zbyt często.

Myślę, że Android może korzystać z systemu przetwarzania opartego na wiadomościach, a jeśli włożysz to wszystko do programu onCreate, możesz napotkać sytuacje, w których błystka zostanie zapełniona po jej wyciągnięciu. Twój słuchacz odpali po ustawieniu lokalizacji przedmiotu. Jest to oczywiście wykształcone przypuszczenie, ale możesz mnie poprawić w tej kwestii.


0

Domyślnie otrzymasz pierwszy element tablicy przędzarki

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

za każdym razem, gdy wybierzesz wartość w pokrętle, otrzymasz wybraną wartość

jeśli chcesz pozycję wybranego elementu, zrób to w ten sposób

pos = spinner.getSelectedItemPosition();

powyższe dwie odpowiedzi dotyczą bez zastosowania detektora

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.