Android Spinner: получить событие изменения выбранного элемента

Как вы можете установить прослушиватель событий для Spinner при изменении выбранного элемента?

В основном то, что я пытаюсь сделать, похоже на это:

spinner1.onSelectionChange = handleSelectionChange;

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

person Soni Ali    schedule 26.08.2009    source источник
comment
Я пробовал эти ответы, но никто не помог. Компонент Once Spinner не поддерживает события щелчка по элементам. Документация по Spinner   -  person    schedule 20.06.2012


Ответы (16)


Некоторые из предыдущих ответов неверны. Они работают для других виджетов и представлений, но документация для В виджете 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().

person znq    schedule 11.11.2009
comment
проблема в том, что метод onItemSelected также вызывается при построении представления. Таким образом, код, который там написан, также выполняется при запуске. Есть ли способ выполнить содержащий код, только если есть реальный выбор элемента, вызванный пользователем? - person Kennethvr; 28.12.2010
comment
на самом деле эту проблему можно решить, поместив setOnItemSelectedListener в метод переопределения OnStart, а не в метод onCreate. глупый я... - person Kennethvr; 28.12.2010
comment
Я поместил слушателя в метод onStart, но он вызывается до того, как пользователь когда-либо что-либо увидит, как и onCreate, поэтому в моем случае, когда кнопка продолжения должна быть невидимой, пока пользователь что-то не выберет, кнопка становится видимым при первом отображении. Вы говорите, что у вас другой опыт? Если да, то что вы делаете по-другому в методе onStart, который мне не хватает? - person Yevgeny Simkin; 28.02.2011
comment
Используйте другое поле внутри вашего анонимного слушателя, чтобы записать первый выбор, и сказать onItemSelected ничего не делать, если выбор не был обнаружен? Просто мысль. - person Sam Svenbjorgchristiensensen; 21.03.2011
comment
Но что, если пользователь выберет элемент по умолчанию, который находится наверху? Тогда onItemSelected(...) не попадает. (Я знаю, потому что только что выяснил это на собственном горьком опыте.) - person Andrew Wyld; 23.03.2012
comment
проблема вызова onItemSelected при создании Activity также обсуждается в stackoverflow.com/questions/2562248/ - person Shine; 10.08.2012
comment
Я бы посоветовал воспользоваться преимуществом вызова setOnItemSelectedListener во время строительства. Используйте это как возможность инициализировать счетчик. Также я видел, что слушатель вызывается независимо от того, добавлен ли он в onStart или onCreate. - person pmont; 04.08.2013
comment
Еще один способ - ввести параметр по умолчанию, например, пожалуйста, выберите поверх массива, и ввести условие в onitemselected, которое не должно делать ничего, если selectedview.gettext возвращает Пожалуйста, выберите. - person Muhammad Ahmed AbuTalib; 14.11.2013
comment
Я устанавливаю переменную класса int на количество слушателей счетчика, которые я буду добавлять в onCreate, и уменьшаю его при вызове каждого onItemSelected. Пока он не достигнет нуля, они просто возвращаются. - person Steve Waring; 21.07.2014
comment
Это нормально? если я не помещаю код в public void onNothingSelected. - person user13926345; 31.07.2020
comment
Не могли бы вы дать свое руководство по следующему вопросу: stackoverflow.com/questions/67985653/ - person SVK; 16.06.2021

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

Примечание. Помните одну вещь.

Событие Spinner OnItemSelectedListener будет выполнено дважды:

  1. Инициализация счетчика
  2. Пользователь выбран вручную

Попытайтесь различить эти два, используя переменную флага.

person Santhosh    schedule 29.04.2010
comment
Мою тоже дважды вызывают! Я не могу понять, как вы их различите? - person MAC; 26.06.2010
comment
Просто установите глобальное логическое значение, например Boolean initialDisplay = true; А затем в вашем onSelect посмотрите, правда ли это, и если это так, не делайте того, что вы собирались делать при выборе, но установите флаг в значение false для следующего его вызова (когда пользователь фактически выбирает). - person Yevgeny Simkin; 28.02.2011
comment
Лучшее объяснение выполнения OnclickListener. - person Pankaj Kumar; 22.08.2011
comment
Я лично потрясен тем, что что-то настолько простое - такой фундаментальный виджет пользовательского интерфейса - чертовски сложно реализовать ... серьезно - насколько сложно было бы создать свойство `` показывать элемент по умолчанию '' и встроить свойство логического флага в объект сам класс ?? Я не фанат Objective C, но скажу, что реализация виджета для iOS занимает примерно 1/10 часть времени, чем в Android. - person Bennett Von Bennett; 15.03.2012
comment
Я полностью согласен с вами @BennettVonBennett. Они могли просто передать нам логическое значение в параметре вместо того, чтобы мы сами реализовали флаг. Это просто глупо, если я чего-то не знаю. - person cantfindaname88; 11.11.2012
comment
Я тоже согласен. Spinner - это один из виджетов, которые облажались. Очень сложно узнать, когда всплывающее окно или выпадающее окно открыто или закрыто. Было бы так сложно добавить событие для этого? Вышеупомянутое решение может ПОЧТИ сказать вам, когда список открыт или закрыт, но имеет три проблемы: (1) нет события для выбора уже выбранного элемента (и список закрывается) и (2) нет события для прерывания (коснитесь off-list, чтобы закрыть его) и (3) onNothingSelected, похоже, никогда не срабатывает для меня. - person Batdude; 02.10.2013
comment
Метод Genia S. не работает очень хорошо, потому что это правда, что в первый раз, когда будет запущено событие onselect (в методе onCreate), вы можете исключить это событие с помощью global var, но если тогда мне нужно выбрать уже выбранный элемент на spinner (элемент по умолчанию, первый) он не будет запущен. Я попытался поставить метку счетчика и исключить ее, но она будет видна в открытом диалоговом окне. Я согласен с @Batdude. Spinner - это один из виджетов, которые облажались. - person jedi; 28.11.2013
comment
Также обратите внимание, что если вы используете метод Genia S и у вас есть несколько счетчиков, использующих один и тот же onItemSelectedListener, вам придется либо отслеживать initialDisplay каждого счетчика отдельно, либо подсчитывать начальные вызовы, пока вы не достигнете количества счетчиков. :-п - person LarsH; 25.07.2019
comment
Не могли бы вы дать свое руководство по следующему вопросу: stackoverflow.com/questions/67985653/ - person SVK; 16.06.2021

Вы можете реализовать класс 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("");
}
person Dhasneem    schedule 27.03.2013

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

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

E.g:

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 должен находиться в области видимости объекта!

person Sampath    schedule 24.11.2011
comment
Вы не можете использовать неконечную переменную в анонимном внутреннем классе. Если переменная iCurrentSelection объявлена ​​в этом анонимном классе, она будет работать нормально. Вы можете инициализировать его значением -1, чтобы код выполнялся при первом вызове. - person dahvyd; 19.05.2012
comment
@dahvyd был правильным, если вы используете это, int должно быть окончательным. В любом случае это действительно хорошо работает. Я отключал поле EditText, если позиция 0 не была выбрана, и если она изменилась, снова включите ее. Спасибо за это. - person natur3; 07.01.2015

Неважно, установите ли вы OnItemSelectedListener в onCreate или onStart - он все равно будет вызываться во время создания или запуска Activity (соответственно).
Таким образом, мы можем установить его в 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;
            }
        });
person Leo Droidcoder    schedule 23.08.2016
comment
Спасибо за использование этого флага. - person Javan R.; 28.06.2017

Найдите свое имя счетчика и найдите идентификатор, затем реализуйте этот метод.

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
    }
});
person droidster.me    schedule 10.12.2012

В документации для виджета-счетчика говорится

Счетчик не поддерживает события щелчка по элементам.

Вы должны использовать setOnItemSelectedListener для решения вашей проблемы.

person johndotnet    schedule 06.11.2009

Для котлина вы можете использовать:

spinner.onItemSelectedListener =  object : AdapterView.OnItemSelectedListener {
    override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
        
    }

    override fun onNothingSelected(p0: AdapterView<*>?) {
        
    }
}

Примечание: для параметров метода onItemSelected я использую имена пользовательских переменных.

person Abduhafiz    schedule 18.07.2020

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

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>
person indrajeet    schedule 27.07.2016

Если вам нужен истинный 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; 
        }
    }

Объекты - ваш друг, используйте их.

person fishjd    schedule 21.11.2016

По умолчанию вы получите первый элемент массива счетчиков через

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

всякий раз, когда вы выбираете значение в счетчике, это даст вам выбранное значение

если вам нужна позиция выбранного элемента, сделайте это так

pos = spinner.getSelectedItemPosition();

приведенные выше два ответа предназначены без применения слушателя

person Adam Noor    schedule 23.01.2020

Это будет работать, инициализируйте счетчик и 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
        }

    });
person sanjay    schedule 09.01.2019

На мой взгляд, лучший способ - иметь flagitemselected = 0; в onCreate(). И на выбранном элементе событие увеличивает этот флаг, то есть flagitemselected++; а затем проверьте

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

Думаю, это поможет.

person Pinakin Kansara    schedule 16.03.2012

Я обнаружил один трюк - поместить ваши setOnItemSelectedListeners в onWindowFocusChanged вместо onCreate. Я пока не обнаружил каких-либо серьезных побочных эффектов для этого. По сути, настраивайте слушателей после того, как окно будет нарисовано. Я не уверен, как часто запускается onWindowFocusChanged, но достаточно легко создать себе переменную блокировки, если вы обнаружите, что она работает слишком часто.

Я думаю, что Android может использовать систему обработки сообщений, и если вы поместите все это в onCreate, вы можете столкнуться с ситуациями, когда счетчик заполняется после того, как он будет отрисован. Итак, ваш слушатель отключится после того, как вы установите местоположение элемента. Это, конечно, обоснованное предположение, но не стесняйтесь поправлять меня по этому поводу.

person Joe Plante    schedule 10.08.2012

Я знаю, что это было давно решено, но у меня есть строка «Выберите строку» в верхней части моих строковых массивов. Затем, когда вы напишете слушателя

yourspinner.onItemSelectedListener = object : OnItemSelectedListener {
            override fun onItemSelected(adapterView: AdapterView<*>?, view: View, i: Int, l: Long) {
                yourvalue = yourspinner.getSelectedItem().toString()

                when(yourvalue){
                    "Please Select" -> // DO nothing
                    else -> // Do something
                }
            }

            override fun onNothingSelected(adapterView: AdapterView<*>?) {
                return
            }
        }

Конечно, вы можете расширить оператор when, чтобы иметь разные ответы или действия.

person UnknownError    schedule 24.11.2020

person    schedule
comment
Это не решает проблему этого обратного вызова, вызываемого при первом запуске счетчика (таким образом, вызывая ответ, который не имеет ничего общего с фактически выбранным элементом). - person Yevgeny Simkin; 28.02.2011