Как получить событие в Android Spinner, когда текущий выбранный элемент снова выбран? - PullRequest
53 голосов
/ 17 марта 2011

Я написал setOnItemSelectedListener для счетчика, чтобы он реагировал на изменение элемента счетчика.Мое требование - когда я снова нажимаю на выбранный элемент, должен появиться тост.Как получить это событие?При повторном щелчке по выбранному элементу спиннер не отвечает.`

    StorageSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener(){

        @Override
        public void onItemSelected(AdapterView adapter, View v, int i, long lng) {              
            Toast.makeText(getApplicationContext(), (CharSequence) StorageSpinner.getSelectedItem(), Toast.LENGTH_SHORT).show();

        }

        @Override
        public void onNothingSelected(AdapterView arg0) {
            Toast.makeText(getApplicationContext(), "Nothing selected", Toast.LENGTH_SHORT).show();

        }
    });  

Ответы [ 19 ]

120 голосов
/ 04 июля 2012

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

import android.content.Context;
import android.util.AttributeSet;
import android.widget.Spinner;


/** Spinner extension that calls onItemSelected even when the selection is the same as its previous value */
public class NDSpinner extends Spinner {

    public NDSpinner(Context context)
    { super(context); }

    public NDSpinner(Context context, AttributeSet attrs)
    { super(context, attrs); }

    public NDSpinner(Context context, AttributeSet attrs, int defStyle)
    { super(context, attrs, defStyle); }

    @Override 
    public void setSelection(int position, boolean animate) {
        boolean sameSelected = position == getSelectedItemPosition();
        super.setSelection(position, animate);
        if (sameSelected) {
            // Spinner does not call the OnItemSelectedListener if the same item is selected, so do it manually now
            getOnItemSelectedListener().onItemSelected(this, getSelectedView(), position, getSelectedItemId());
        }
    } 

    @Override
    public void setSelection(int position) {
        boolean sameSelected = position == getSelectedItemPosition();
        super.setSelection(position);
        if (sameSelected) {
            // Spinner does not call the OnItemSelectedListener if the same item is selected, so do it manually now
            getOnItemSelectedListener().onItemSelected(this, getSelectedView(), position, getSelectedItemId());
        }
    }

}
24 голосов
/ 14 июня 2013

попробуйте

public class MySpinner extends Spinner{

OnItemSelectedListener listener;

    public MySpinner(Context context, AttributeSet attrs)
    {
        super(context, attrs);
    }

    @Override
    public void setSelection(int position)
    {
        super.setSelection(position);

        if (position == getSelectedItemPosition())
        {
            listener.onItemSelected(null, null, position, 0);
        }       
    }

    public void setOnItemSelectedListener(OnItemSelectedListener listener)
    {
        this.listener = listener;
    }
}
15 голосов
/ 07 октября 2011

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

package com.mitosoft.ui.widgets;

import java.lang.reflect.Method;
import android.content.Context;
import android.content.DialogInterface;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.AdapterView;
import android.widget.Spinner;

//com.mitosoft.ui.widgets.NoDefaultSpinner
public class NoDefaultSpinner extends Spinner {

    private int lastSelected = 0;
    private static Method s_pSelectionChangedMethod = null;


    static {        
        try {
            Class noparams[] = {};
            Class targetClass = AdapterView.class;

            s_pSelectionChangedMethod = targetClass.getDeclaredMethod("selectionChanged", noparams);            
            if (s_pSelectionChangedMethod != null) {
                s_pSelectionChangedMethod.setAccessible(true);              
            }

        } catch( Exception e ) {
            Log.e("Custom spinner, reflection bug:", e.getMessage());
            throw new RuntimeException(e);
        }
    }

    public NoDefaultSpinner(Context context) {
        super(context);
    }

    public NoDefaultSpinner(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public NoDefaultSpinner(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public void testReflectionForSelectionChanged() {
        try {
            Class noparams[] = {};          
            s_pSelectionChangedMethod.invoke(this, noparams);
        } catch (Exception e) {
            Log.e("Custom spinner, reflection bug: ", e.getMessage());
            e.printStackTrace();                
        }
    } 




    @Override
    public void onClick(DialogInterface dialog, int which) {    
        super.onClick(dialog, which);
            if(lastSelected == which)
                testReflectionForSelectionChanged();

            lastSelected = which;
    }
}
7 голосов
/ 05 ноября 2013

Я решил, что оставлю обновленный ответ для тех, кто работает над более новыми версиями Android.

Я собрал вместе функцию из приведенных выше ответов, которая будет работать как минимум для 4.1.2 и 4.3 (устройства, которые япроверено на).Эта функция не использует отражение, но вместо этого отслеживает последний выбранный индекс, поэтому ее можно безопасно использовать, даже если SDK меняет то, как классы расширяют друг друга.

import android.content.Context;
import android.util.AttributeSet;
import android.widget.Spinner;

public class SelectAgainSpinner extends Spinner {

    private int lastSelected = 0;

    public SelectAgainSpinner(Context context)
    { super(context); }

    public SelectAgainSpinner(Context context, AttributeSet attrs)
    { super(context, attrs); }

    public SelectAgainSpinner(Context context, AttributeSet attrs, int defStyle)
    { super(context, attrs, defStyle); }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        if(this.lastSelected == this.getSelectedItemPosition() && getOnItemSelectedListener() != null)
            getOnItemSelectedListener().onItemSelected(this, getSelectedView(), this.getSelectedItemPosition(), getSelectedItemId());
        if(!changed)
            lastSelected = this.getSelectedItemPosition();

        super.onLayout(changed, l, t, r, b);
    } 
}
5 голосов
/ 29 мая 2012

для новых платформ попробуйте добавить это в решение Dimitar. Я думаю, что это работает:)

(необходимо переопределить onLayout и удалить метод onClick)

    @Override
public void onClick(DialogInterface dialog, int which) {    
    super.onClick(dialog, which);
}

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
    if(this.lastSelected == this.getSelectedItemPosition())
        testReflectionForSelectionChanged();
    if(!changed)
        lastSelected = this.getSelectedItemPosition();

    super.onLayout(changed, l, t, r, b);
} 
3 голосов
/ 18 марта 2011

Я обнаружил, что OnItemSelectedListener не будет вызываться, если тот же элемент снова будет выбран в счетчике.Когда я нажимаю на спиннер и снова выбираю то же значение, метод OnItemSelectedListener не вызывается.Люди не ожидают, что что-то случится, если они нажмут на выбор, который уже активен согласно дизайну пользовательского интерфейса.

2 голосов
/ 12 июня 2016

Это не полное решение , но оно работает, если вы хотите вызвать его, только когда возвращаетесь к своему фрагменту / деятельности откуда угодно.

Учитывая mSpinner - это ваше представление Spinner, мы называем его слушателем так:

@Override public void onResume()
    {
        if ( mSpinner.getCount() > 0 )
        {
            mSpinner.getOnItemSelectedListener()
                    .onItemSelected( mSpinner, null, mSpinner.getSelectedItemPosition(), 0 );
        }
        super.onResume();
    }
2 голосов
/ 14 октября 2011

@ Димитр. ВАУ, блестящая работа. Спасибо за это. Я не могу высказать ваше решение (недостаточно очков), но класс NoDefaultSpinner РАБОТАЕТ. Проблема заключалась только в одном: поскольку вы вызываете super.onClick, а затем testReflectionForSelectionChanged () внутри OnClick, вы получите обработчик onItemSelected для счетчика, вызываемого дважды, если выбор действительно изменяется (в то время как функциональность верна, если тот же пункт повторно выбран). Я решил это, взломав это. Я добавил переопределение onTouchEvent, которое записывало, к какому элементу прикоснулись, и проверил, изменилось ли это в «onClick»:

private Object ob=null; //class level variable
 @Override
public boolean onTouchEvent(MotionEvent m)
{
    if (m.getAction()==MotionEvent.ACTION_DOWN)
    {
        ob=this.getSelectedItem();
    }
    return super.onTouchEvent(m);
}
@Override
public void onClick(DialogInterface dialog, int which) {    
    super.onClick(dialog, which);
    if (this.getSelectedItem().equals(ob))
        testReflectionForSelectionChanged();
}
1 голос
/ 25 ноября 2016

Привет, мужик, у меня это сработало:

ArrayAdapter<String> adaptador1 = new ArrayAdapter<String>( Ed_Central.this, 
                                                            android.R.layout.simple_spinner_item,
                                                            datos1
                                                            );
        lista1.setAdapter( adaptador1 );

        lista1.setOnItemSelectedListener( new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected( AdapterView<?> parent, View view, int position, long id ) {

                lista1.setSelection( 0 );

                switch ( position ) {
                    case 1:
                        Toast.makeText( getApplicationContext(), "msg1", Toast.LENGTH_SHORT ).show();
                        break;
                    case 2:
                        Toast.makeText( getApplicationContext(), "msg2", Toast.LENGTH_SHORT ).show();
                        break;
                    case 3:
                        Toast.makeText( getApplicationContext(), "msg3", Toast.LENGTH_SHORT ).show();
                        break;

                    default:
                        break;
                }
            }

Всегда адаптер будет в положении "0", и вы можете показать свой тост.

1 голос
/ 25 сентября 2016

Это простое решение, потому что можно программно установить «выбранный элемент» на основе «onTouch», например так:

spinnerobject.setOnTouchListener(new AdapterView.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {

            final int MAKE_A_SELECTION = 1; //whatever index that is the normal starting point of the spinner.
            spinnerObject.setSelection(MAKE_A_SELECTION);
            return false;
        }
    });

В этом (1) счетчике есть небольшой штрафтекст изменится на значение по умолчанию непосредственно перед отображением строк счетчика, и (2) этот элемент по умолчанию будет частью списка.Возможно, кто-то может добавить, как отключить конкретный элемент для счетчика?

Вообще говоря, поскольку выбор счетчика может выполнить повторяемое событие (например, начало поиска), отсутствие возможности повторно выбрать элемент в счетчикедействительно отсутствует функция / ошибка в классе Spinner, ошибка, которую разработчики Android должны исправить как можно скорее.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...