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


407

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

По сути, я пытаюсь сделать что-то похожее на это:

spinner1.onSelectionChange = handleSelectionChange;

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

Я пробовал эти ответы, но никто не помог. Однажды компонент Spinner не поддерживает события щелчка элемента. Документация 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 также вызывается при построении представления. Таким образом, код, который там написан, также запускается при запуске. Есть ли способ выполнить содержащий код только в том случае, если пользователь выбрал реальный выбор элемента?
Kennethvr

39
на самом деле эту проблему можно решить, поместив setOnItemSelectedListener в переопределенный метод OnStart, а не в метод onCreate. глупый я ...
Kennethvr

16
Я поместил слушатель в метод onStart, но он вызывается до того, как пользователь когда-либо увидит что-либо, как и в случае с onCreate, поэтому в моем случае кнопка «продолжить», которая должна быть невидимой, пока пользователь не выберет что-то, кнопка становится видимой при первоначальном отображении. Вы говорите, что ваш опыт отличается? Если так, что вы делаете по-другому в методе onStart, который мне не хватает?
Евгений Симкин

7
Используйте другое поле в вашем анонимном слушателе, чтобы записать первый выбор, и скажите, чтобы onItemSelected ничего не делало, если выбор не был обнаружен? Просто мысль.
Сэм Свенбьоргхристиансенсен,

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
Просто установите глобальный логический тип, такой как Boolean initialDisplay = true; И затем в вашем onSelect посмотрите, истинно ли это, и если это так, не делайте того, что вы собирались сделать при выборе, но установите флаг в false, чтобы в следующий раз он вызывался (когда пользователь фактически выбирает).
Евгений Симкин

Лучшее объяснение о выполнении OnclickListener.
Панкадж Кумар

6
Я лично потрясен тем, что что-то такое простое - такой фундаментальный виджет пользовательского интерфейса - так чертовски сложно реализовать ... серьезно - насколько трудно было бы создать свойство «показ элемента по умолчанию» и встроить свойство логического флага в объект сам класс ?? Я не фанат Objective C, но скажу, что реализация виджета iOS занимает примерно 1/10 времени, чем в Android.
Беннет фон Беннетт

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

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

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 - он все равно будет вызываться во время создания или запуска 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;
            }
        });

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. Я не нашел никаких побочных эффектов, если бы сделал это таким образом. По сути, настройте слушателей после того, как окно будет нарисовано. Я не уверен, как часто запускается onWindowFocusChanged, но достаточно легко создать себе переменную блокировки, если вы обнаружите, что она работает слишком часто.

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


0

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

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

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

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

pos = spinner.getSelectedItemPosition();

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.