Android Spinner:获取选定的项目更改事件


407

当所选项目更改时,如何设置微调框的事件侦听器?

基本上我想要做的是类似于以下内容:

spinner1.onSelectionChange = handleSelectionChange;

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

我已经尝试过这些答案,但是没有人提供帮助。一旦Spinner组件不支持项目点击事件。微调文档

Answers:


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 2010年

39
实际上,可以通过将setOnItemSelectedListener放在重写OnStart方法中而不是onCreate方法中来解决该问题。愚蠢的我...
Kennethvr 2010年

16
我已经将侦听器置于onStart方法中,但是它在用户看到任何东西之前就被调用,就像onCreate一样,因此,在我的情况下,“继续”按钮在用户选择某些内容之前是不可见的,初始显示时,该按钮将可见。您是说您的经历与众不同吗?如果是这样,您在我缺少的onStart方法中做了什么不同的工作?
Yevgeny Simkin

7
在匿名侦听器中使用另一个字段来记录第一个选择,并告诉onItemSelected除非遇到选择,否则不要执行任何操作?只是一个想法。
2011年

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

注意:请记住一件事。

Spinner OnItemSelectedListener事件将执行两次:

  1. 微调器初始化
  2. 用户手动选择

尝试通过使用标志变量来区分两者。


3
我的也被叫过两次!我不知道你如何区分两者?
MAC

18
只需设置一个全局布尔值,例如Boolean initialDisplay = true;。然后在您的onSelect中查看它是否为true,如果不正确,则不要在select上执行任何其他操作,而是将标志设置为false,以备下次调用(当用户实际选择时)。
叶夫根尼·辛金

有关执行OnclickListener的最佳说明。
Pankaj Kumar

6
我个人感到震惊的是,如此简单的东西-这样的基本UI控件-很难实现……严重–很难建立“默认显示项”属性并将Boolean标志属性构建到对象中类本身?我不喜欢Objective C,但是我想说iOS小部件的实现大约是Android的1/10。
Bennett Von Bennett

4
我也同意。Spinner是一个搞砸的小部件。很难知道何时打开或关闭弹出窗口。为此添加事件会如此困难吗?上面的解决方案可以ALMOST告诉您何时打开或关闭列表,但是存在三个问题:(1)没有选择已选择项目的事件(列表关闭),(2)没有中止事件(触摸取消列表以将其关闭)和(3)onNothingSelected似乎对我不起作用。
Batdude

19

您可以AdapterView.OnItemSelectedListener在Activity中实现类。

然后使用下面的行 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必须为final。无论如何,它确实运行良好。如果未选择位置0,并且禁用了它,则我将禁用EditText字段,然后重新启用它。谢谢你
natur3,2015年

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

您可以在onCreate或onStart中设置OnItemSelectedListener无关紧要-它仍将在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
感谢您使用此标志。
Javan R.17年

7

Spinner-widget的文档说

微调框不支持项目点击事件。

您应该使用它setOnItemSelectedListener来解决您的问题。


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

1
这并没有解决在首次启动微调器时调用此回调的问题(因此引发与实际选择的项目无关的响应)。
Yevgeny Simkin

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

以上两个答案适用于不应用监听器的情况

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.