Android Spinner: Nhận sự kiện thay đổi mục đã chọn


407

Làm cách nào bạn có thể đặt trình nghe sự kiện cho Spinner khi mục được chọn thay đổi?

Về cơ bản những gì tôi đang cố gắng làm là một cái gì đó tương tự như thế này:

spinner1.onSelectionChange = handleSelectionChange;

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

Tôi đã thử những câu trả lời này, nhưng không ai hữu ích. Khi thành phần Spinner không hỗ trợ các sự kiện nhấp vào mục. Tài liệu Spinner

Câu trả lời:


812

Một số câu trả lời trước không đúng. Chúng hoạt động cho các tiện ích và chế độ xem khác, nhưng tài liệu về tiện ích Spinner nêu rõ:

Một spinner không hỗ trợ các sự kiện bấm vào mục. Gọi phương thức này sẽ đưa ra một ngoại lệ.

Thay vào đó, sử dụng tốt hơn 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
    }

});

Điều này làm việc cho tôi.

Lưu ý rằng phương thức onItemSelected cũng được gọi khi chế độ xem đang được xây dựng, vì vậy bạn có thể xem xét đưa nó vào trong onCreate()cuộc gọi phương thức.


47
vấn đề với điều này là phương thức onItemSelected cũng được gọi khi chế độ xem đang được xây dựng. Vì vậy, mã được viết trong đó cũng được thực thi khi khởi động. Có cách nào để thực thi mã chứa chỉ khi có một lựa chọn vật phẩm thực sự được người dùng gọi ra không?
Kennethvr

39
thực sự vấn đề đó có thể được giải quyết bằng cách đặt setOnItemSelectedListener trong phương thức ghi đè OnStart chứ không phải trong phương thức onCreate. ngu ngốc cho tôi ...
Kennethvr

16
Tôi đã đưa người nghe vào phương thức onStart, nhưng nó được gọi trước khi người dùng thấy bất cứ điều gì, giống như onCreate, vì vậy, trong trường hợp của tôi, nút "tiến hành" có nghĩa là vô hình cho đến khi người dùng chọn thứ gì đó, nút được hiển thị khi hiển thị ban đầu. Bạn đang nói kinh nghiệm của bạn là khác nhau? Nếu vậy, bạn đang làm gì khác trong phương thức onStart mà tôi đang thiếu?
Yevgeny Simkin

7
Sử dụng một trường khác bên trong trình nghe ẩn danh của bạn để ghi lại lựa chọn đầu tiên và nói với onItemSelected không làm gì trừ khi gặp phải lựa chọn? Chỉ là một ý nghĩ.
Sam Svenbjorgchristiensensen

4
Nhưng nếu người dùng chọn mục "mặc định", mục nào sẽ đứng đầu? Sau đó onItemSelected(...)là không đánh. (Tôi biết vì tôi chỉ phát hiện ra điều này một cách khó khăn.)
Andrew Wyld

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

Lưu ý: Hãy nhớ một điều.

OnItemSelectedListenerSự kiện Spinner sẽ thực thi hai lần:

  1. Spinner khởi tạo
  2. Người dùng chọn thủ công

Cố gắng phân biệt hai cái đó bằng cách sử dụng biến cờ.


3
Của tôi được gọi hai lần quá! Tôi không thể tìm ra làm thế nào bạn phân biệt giữa hai?
MAC

18
Chỉ cần đặt Boolean toàn cầu như Boolean initDisplay = true; Và sau đó, trong phần chọn của bạn, hãy xem nó có đúng không và nếu đúng, đừng làm bất cứ điều gì khác mà bạn sẽ làm khi chọn nhưng đặt cờ thành sai, cho lần tiếp theo nó được gọi (khi người dùng thực sự chọn).
Yevgeny Simkin

Giải thích tốt nhất về việc thực thi OnclickListener.
Pankaj Kumar

6
Cá nhân tôi đã kinh hoàng rằng một cái gì đó rất đơn giản - một tiện ích UI cơ bản như vậy - rất khó thực hiện ... nghiêm túc - việc xây dựng một thuộc tính 'mục hiển thị mặc định' khó như thế nào và để xây dựng thuộc tính cờ Boolean vào đối tượng lớp mình ?? Tôi không phải là fan hâm mộ của Objective C nhưng tôi sẽ nói rằng việc triển khai widget iOS mất khoảng 1/10 thời gian trong Android.
Bennett Von Bennett

4
Tôi cũng đồng ý. Spinner là một tiện ích bắt vít. Rất khó để biết khi nào cửa sổ bật lên hoặc thả được mở hoặc đóng. Sẽ rất khó để thêm một sự kiện cho điều này? Giải pháp trên có thể ALMOST cho bạn biết khi danh sách được mở hoặc đóng nhưng có ba vấn đề: (1) không có sự kiện nào để chọn mục đã chọn (và danh sách đóng) và (2) không có sự kiện nào để hủy bỏ (chạm ngoài danh sách để đóng nó) và (3) onNothSelected dường như không bao giờ kích hoạt cho tôi.
Batdude

19

Bạn có thể thực hiện AdapterView.OnItemSelectedListenerlớp trong Hoạt động của bạn.

Và sau đó sử dụng dòng dưới đây trong onCreate()

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

Sau đó ghi đè hai phương thức này:

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

Bạn có thể tránh việc OnItemSelectedListener () được gọi bằng một kiểm tra đơn giản: Lưu chỉ số lựa chọn hiện tại vào một biến số nguyên và kiểm tra bên trong onItemSelected (..) trước khi làm bất cứ điều gì.

Ví dụ:

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

Vì lý do iCurrentSelectionnên trong phạm vi đối tượng để làm việc này!


1
Bạn không thể sử dụng một biến không phải là cuối cùng trong một lớp bên trong ẩn danh. Nếu iCurrentSelectionbiến được khai báo trong lớp ẩn danh này, nó sẽ hoạt động tốt. Bạn có thể khởi tạo nó thành -1 để mã được thực thi trong cuộc gọi đầu tiên.
dahvyd

2
@dahvyd đã đúng nếu bạn sử dụng int này là cuối cùng. Trong mọi trường hợp nó hoạt động thực sự tốt. Tôi đã vô hiệu hóa trường EditText nếu vị trí 0 không được chọn và nếu nó thay đổi, hãy bật lại. Cám ơn vì cái này.
natur3

8

Tìm tên spinner của bạn và tìm id sau đó thực hiện phương pháp này.

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

Bạn không đặt OnItemSelectedListener trong onCreate hoặc onStart - nó vẫn sẽ được gọi trong quá trình tạo Activity hoặc bắt đầu (tương ứng).
Vì vậy, chúng ta có thể thiết lập nó trong onCreate (và KHÔNG trong onStart!).
Chỉ cần thêm một cờ để tìm ra khởi tạo đầu tiên:

private Spinner mSpinner;
private boolean mSpinnerInitialized;

sau đó trong onCreate (hoặc onCreateView) chỉ:

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
Cảm ơn bạn đã sử dụng cờ này.
Javan R.

7

Các tài liệu cho tiện ích spinner nói

Một spinner không hỗ trợ các sự kiện bấm vào mục.

Bạn nên sử dụng setOnItemSelectedListenerđể xử lý vấn đề của bạn.


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

1
Điều này không giải quyết được vấn đề gọi lại này khi spinner được bắt đầu lần đầu tiên (do đó gây ra phản hồi không liên quan gì đến một mục thực sự được chọn).
Yevgeny Simkin

4

lấy một biến toàn cục để lựa chọn spinner hiện tại:

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

Nếu bạn muốn một onChangedListener () thực sự. Lưu trữ giá trị ban đầu trong trình xử lý và kiểm tra xem nó đã thay đổi chưa. Nó là đơn giản và không yêu cầu một biến toàn cầu. Hoạt động nếu bạn có nhiều hơn một spinner trên trang.

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

Đối tượng là bạn của bạn, sử dụng chúng.


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

Điều này sẽ làm việc nội tâm hóa spinner và findviewbyid và sử dụng nó sẽ hoạt động

    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

Cách tốt nhất những gì tôi nghĩ rằng sẽ có một flagitemselected = 0;trong onCreate(). Và trên mục được chọn tăng sự kiện đó là cờ flagitemselected++; và sau đó kiểm tra

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

Điều này sẽ giúp tôi đoán.


0

Một mẹo tôi tìm thấy là đặt setOnItemSelectedListener của bạn vào onWindowF FocusChanged thay vì onCreate. Tôi chưa tìm thấy bất kỳ tác dụng phụ xấu nào để làm theo cách này. Về cơ bản, thiết lập trình nghe sau khi cửa sổ được rút ra. Tôi không chắc chắn tần suất chạy trênWindowF FocusChanged, nhưng đủ dễ để tạo cho mình một biến khóa nếu bạn thấy nó chạy quá thường xuyên.

Tôi nghĩ rằng Android có thể đang sử dụng một hệ thống xử lý dựa trên thông báo và nếu bạn đặt tất cả vào onCreate, bạn có thể gặp phải tình huống mà spinner được tạo ra sau khi được rút ra. Vì vậy, người nghe của bạn sẽ tắt sau khi bạn đặt vị trí mục. Đây là một phỏng đoán có giáo dục, tất nhiên, nhưng cảm thấy tự do để sửa chữa tôi về điều này.


0

Theo mặc định, bạn sẽ nhận được mục đầu tiên của mảng spinner thông qua

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

Bất cứ khi nào bạn chọn giá trị trong spinner, nó sẽ cung cấp cho bạn giá trị được chọn

Nếu bạn muốn vị trí của mục đã chọn thì hãy làm như thế

pos = spinner.getSelectedItemPosition();

Hai câu trả lời trên là dành cho người nghe mà không áp dụng

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.