Android Spinner: отримайте подію зміни вибраного елемента


407

Як ви можете встановити слухач події для Spinner, коли вибраний елемент змінюється?

В основному те, що я намагаюся зробити, є щось подібне до цього:

spinner1.onSelectionChange = handleSelectionChange;

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

Я пробував ці відповіді, але ніхто не був корисним. Як тільки компонент Spinner не підтримує події клацання предмета. Документація до

Відповіді:


812

Деякі з попередніх відповідей невірні. Вони працюють для інших віджетів та представлень, але в документації на віджет Spinner чітко зазначено:

Шпинер не підтримує події клацання елемента. Виклик цього методу призведе до виключення.

Краще використовувати 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
    }

});

Це працює для мене.

Зауважте, що метод onItemSelected також викликається під час створення представлення, тому ви можете розглянути можливість його введення у onCreate()виклик методу.


47
Проблема в тому, що метод onItemSelected також викликається під час створення представлення. Тож код, який там записаний, також виконується при запуску. Чи існує спосіб виконання вмістуючого коду лише за умови, що користувач реально вибирає предмет?
Кеннетвр

39
насправді цю проблему можна вирішити, поставивши setOnItemSelectedListener в метод заміщення OnStart, а не в метод onCreate. дурний мене ...
Кеннетвр

16
Я поставив слухача методом onStart, але він викликається, перш ніж користувач коли-небудь зможе побачити що-небудь, як і onCreate є, тому в моєму випадку, коли кнопка "продовжити", яка повинна бути невидимою, поки користувач щось не вибере, кнопка стає видимою при первинному відображенні. Ви кажете, що ваш досвід відрізняється? Якщо так, то що ви робите по-іншому в методі onStart, який мені не вистачає?
Євгеній Сімкін

7
Використовуйте інше поле всередині вашого анонімного слухача, щоб записати перший вибір, і скажіть onItemSelected, щоб нічого не робити, якщо не відбувся вибір? Просто думка.
Sam Svenbjorgchristiensensen

4
Але що робити, якщо користувач вибере пункт "за замовчуванням", той, що знаходиться вгорі? Тоді onItemSelected(...)не потрапляють. (Я знаю, тому що я щойно з'ясував це важким шляхом.)
Ендрю Вілд

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

Примітка. Запам’ятайте одне.

OnItemSelectedListenerПодія Spinner виконується двічі:

  1. Ініціалізація спінера
  2. Користувача вибирають вручну

Спробуйте розмежувати ці два, використовуючи змінну прапора.


3
Міну теж дзвонять двічі! Я не можу зрозуміти, як ви розмежовуєте це?
MAC

18
Просто встановіть такий глобальний булевий, як булевий початковийDisplay = true; А потім у своєму onSelect перевірте, чи це правда, і якщо це так, не робіть нічого іншого, що ви збиралися зробити у виборі, але встановіть прапор на значення false, коли наступний раз він буде називатися (коли користувач насправді вибере).
Євген Симкін

Найкраще пояснення щодо виконання OnclickListener.
Панкай Кумар

6
Мене особисто вражають, що щось таке просте - такий фундаментальний віджет інтерфейсу користувача - настільки криваво важко реалізувати ... серйозно - як важко було б побудувати властивість "елемент, що відображає за замовчуванням" та вбудувати властивість булевого прапора в об'єкт сам клас ?? Я не шанувальник Objective C, але скажу, що реалізація віджетів iOS займає приблизно 10/10 разів, ніж це робиться в Android.
Bennett Von Bennett

4
Я також згоден. Spinner - це один відкручений віджет. Дуже важко дізнатися, коли спливаюче вікно або крапля відкрита чи закрита. Чи було б так важко додати подію для цього? Вищевказане рішення може ТОЛЬКО сказати вам, коли список відкритий чи закритий, але є три проблеми: (1) немає події для вибору вже вибраного елемента (і список закривається) та (2) немає події для відмови (торкніться) поза списком, щоб закрити його) і (3) onNothingSelected ніколи не здається для мене стрільбою.
Batdude

19

Ви можете реалізувати AdapterView.OnItemSelectedListener клас у своїй діяльності.

А потім використовуйте рядок нижче onCreate()

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

Потім замініть ці два способи:

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

Ви можете уникнути виклику OnItemSelectedListener () за допомогою простої перевірки: Зберігайте поточний індекс вибору в цілочисленній змінній та перевіряйте в onItemSelected (..), перш ніж робити що-небудь.

Наприклад:

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

Тому що це iCurrentSelectionповинно бути в об'єкті, щоб це працювало!


1
Не можна використовувати не остаточну змінну в анонімному внутрішньому класі. Якщо iCurrentSelectionзмінна оголошена в рамках цього анонімного класу, вона буде добре працювати. Ви можете ініціалізувати його до -1, щоб код виконувався під час першого дзвінка.
дахвід

2
@dahvyd був правильним, якщо ви користуєтесь цим, int повинен бути остаточним. У будь-якому випадку це працює дуже добре. Я відключив поле EditText, якщо позиція 0 не була обрана і якщо вона змінилася, повторно ввімкніть її. Дякую за це
natur3

8

Знайдіть своє ім'я спінера та знайдіть ідентифікатор, а потім застосуйте цей метод.

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

Не має значення, чи встановите OnItemSelectedListener в onCreate або onStart - він все одно буде викликатися під час створення або запуску (відповідно).
Таким чином, ми можемо встановити його в onCreate (а НЕ в onStart!).
Просто додайте прапор, щоб визначити першу ініціалізацію:

private Spinner mSpinner;
private boolean mSpinnerInitialized;

тоді в onCreate (або onCreateView) просто:

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
Дякуємо, що використовували цей прапор.
Яван Р.

7

Документи для спінер-віджета говорить

Шпинер не підтримує події клацання елемента.

Ви повинні використовувати setOnItemSelectedListenerдля вирішення своєї проблеми.


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

1
Це не стосується проблеми виклику цього зворотного дзвінка під час першого запуску спінера (таким чином провокуючи відповідь, яка не має нічого спільного з елементом, який насправді обраний).
Євгеній Сімкін

4

взяти глобальну змінну для поточного вибору спінера:

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

Якщо ви хочете справжнього onChangedListener (). Збережіть початкове значення в обробнику і перевірте, чи воно змінилося. Це просто і не вимагає глобальної змінної. Працює, якщо у вас є більше одного спінера на сторінці.

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

Об'єкти - твій друг, використовуй їх.


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

Це допоможе активізувати спінер і findviewbyid і використовувати це він буде працювати

    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

Найкращий спосіб , що я думаю , що буде мати flagitemselected = 0;ін onCreate(). І на пункт вибраного приросту події цей прапор, тобто flagitemselected++; а потім перевірити

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

Це допоможе здогадуватися.


0

Я знайшов один трюк - помістити ваш setOnItemSelectedListeners в onWindowFocusChanged замість onCreate. Я не знайшов жодних поганих побічних ефектів, щоб зробити це таким чином. В основному, налаштуйте слухачів після того, як з'явиться вікно. Я не впевнений, як часто він працює на WindowFocusChanged, але досить просто створити собі змінну блокування, якщо ви виявите, що вона працює занадто часто.

Я думаю, що в Android може бути використана система обробки на основі повідомлень, і якщо ви вкладете все це в onCreate, ви можете зіткнутися з ситуаціями, коли спінер заповнюється після його залучення. Отже, ваш слухач вимкнеться після встановлення місця розташування елемента. Це, звичайно, освічена здогадка, але сміливо виправляйте мене з цього приводу.


0

За замовчуванням ви отримаєте перший елемент спінерного масиву наскрізь

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

щоразу, коли ви вибрали значення в спінері, це дасть вам вибране значення

якщо ви хочете розташувати вибраний елемент, виконайте це так

pos = spinner.getSelectedItemPosition();

вищевказані дві відповіді - це не застосовуючи слухача

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.