Android Spinner: Dapatkan acara perubahan item yang dipilih

407

Bagaimana Anda dapat mengatur pendengar acara untuk Spinner ketika item yang dipilih berubah?

Pada dasarnya apa yang saya coba lakukan adalah sesuatu yang mirip dengan ini:

spinner1.onSelectionChange = handleSelectionChange;

void handleSelectionChange(Object sender){
    //handle event
}
Soni Ali
sumber
Saya sudah mencoba jawaban ini, tetapi tidak ada yang membantu. Setelah komponen Spinner tidak mendukung acara klik item. Dokumentasi Spinner

Jawaban:

812

Beberapa jawaban sebelumnya salah. Mereka berfungsi untuk widget dan tampilan lain, tetapi dokumentasi untuk widget Spinner dengan jelas menyatakan:

Spinner tidak mendukung acara klik item. Memanggil metode ini akan menimbulkan pengecualian.

Lebih baik gunakan OnItemSelectedListener () sebagai gantinya:

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
    }

});

Ini bekerja untuk saya.

Perhatikan bahwa metode onItemSelected juga dipanggil saat tampilan sedang dibuat, sehingga Anda dapat mempertimbangkan untuk memasukkannya ke dalam onCreate()pemanggilan metode.

znq
sumber
47
masalah dengan ini adalah bahwa metode onItemSelected juga dipanggil ketika tampilan sedang dibangun. Jadi kode yang tertulis di sana dijalankan juga saat startup. Apakah ada cara mengeksekusi kode yang berisi hanya jika ada pemilihan item nyata yang diminta oleh pengguna?
Kennethvr
39
sebenarnya masalah itu dapat diselesaikan dengan meletakkan setOnItemSelectedListener dalam metode OnStart override dan bukan pada metode onCreate. bodohnya aku ...
Kennethvr
16
Saya telah memasukkan pendengar dalam metode onStart, tetapi dipanggil sebelum pengguna melihat apa pun, seperti onCreate, jadi, dalam kasus saya di mana tombol "lanjutkan" yang dimaksudkan untuk tidak terlihat sampai pengguna memilih sesuatu, tombol dibuat terlihat pada tampilan awal. Apakah Anda mengatakan pengalaman Anda berbeda? Jika demikian, apa yang Anda lakukan secara berbeda dalam metode onStart yang saya lewatkan?
Yevgeny Simkin
7
Gunakan bidang lain di dalam pendengar anonim Anda untuk merekam pilihan pertama, dan beri tahu onItemSelected untuk tidak melakukan apa-apa kecuali suatu seleksi telah ditemukan? Hanya pemikiran saja.
Sam Svenbjorgchristiensensen
4
Tetapi bagaimana jika pengguna memilih item "default", yang di atas? Maka onItemSelected(...)tidak kena. (Saya tahu karena saya baru menemukan ini dengan cara yang sulit.)
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;
    } 
}); 

Catatan: Ingat satu hal.

OnItemSelectedListenerAcara Spinner akan dieksekusi dua kali:

  1. Inisialisasi spinner
  2. Pengguna dipilih secara manual

Cobalah untuk membedakan keduanya dengan menggunakan variabel flag.

Santhosh
sumber
3
Milik saya dipanggil dua kali juga! Saya tidak tahu bagaimana Anda membedakan keduanya?
MAC
18
Cukup atur Boolean global seperti Boolean initialDisplay = true; Dan kemudian di onSelect Anda, lihat apakah itu benar dan jika benar, jangan lakukan apa pun yang akan Anda lakukan pada pilih tetapi tetapkan bendera ke false, untuk kali berikutnya itu disebut (ketika pengguna benar-benar memilih).
Yevgeny Simkin
Penjelasan terbaik tentang eksekusi OnclickListener.
Pankaj Kumar
6
Saya pribadi terkejut bahwa sesuatu yang sangat sederhana - seperti widget UI mendasar - sangat sulit untuk diimplementasikan ... serius - betapa sulitnya membangun properti 'item penunjukan standar' dan membangun properti bendera Boolean ke objek kelas itu sendiri ?? Saya bukan penggemar Objective C tetapi saya akan mengatakan bahwa implementasi widget iOS membutuhkan waktu 1/10 kali lebih baik di Android.
Bennett Von Bennett
4
Saya juga setuju. Spinner adalah salah satu widget yang kacau. Sangat sulit untuk mengetahui kapan popup atau drop terbuka atau tertutup. Apakah akan sangat sulit untuk menambahkan acara untuk ini? Solusi di atas dapat HAMPIR memberitahu Anda ketika daftar terbuka atau tertutup tetapi memiliki tiga masalah: (1) tidak ada acara untuk memilih item yang sudah dipilih (dan daftar ditutup) dan (2) tidak ada acara untuk dibatalkan (sentuh off-list untuk menutupnya) dan (3) onNothingSelected sepertinya tidak pernah memecat saya.
Batdude
19

Anda dapat mengimplementasikan AdapterView.OnItemSelectedListenerkelas dalam Aktivitas Anda.

Dan kemudian gunakan baris di bawah ini onCreate()

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

Kemudian timpa kedua metode ini:

public void onItemSelected(AdapterView<?> parent, View v, int position, long id) {
    selection.setText(items[position]);
}

public void onNothingSelected(AdapterView<?> parent) {
    selection.setText("");
}
Dhasneem
sumber
16

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

Anda dapat menghindari OnItemSelectedListener () dipanggil dengan cek sederhana: Simpan indeks pilihan saat ini dalam variabel integer dan periksa di dalam onItemSelected (..) sebelum melakukan apa pun.

Misalnya:

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

Karena iCurrentSelectionharus dalam lingkup objek agar ini bekerja!

Sampath
sumber
1
Anda tidak dapat menggunakan variabel non-final dalam kelas batin anonim. Jika iCurrentSelectionvariabel dideklarasikan dalam kelas anonim ini, ia akan berfungsi dengan baik. Anda dapat menginisialisasi ke -1 sehingga kode dieksekusi pada panggilan pertama.
dahvyd
2
@dahvyd benar jika Anda menggunakan int ini harus final. Bagaimanapun itu bekerja dengan sangat baik. Saya menonaktifkan bidang EditText jika posisi 0 tidak dipilih dan jika diubah, aktifkan kembali. Terima kasih untuk ini.
natur3
8

Temukan nama pemintal Anda dan temukan id kemudian terapkan metode ini.

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
    }
});
droidster.me
sumber
8

Tidak masalah apakah Anda mengatur OnItemSelectedListener di onCreate atau onStart - itu akan tetap dipanggil selama pembuatan atau mulai Kegiatan (masing-masing).
Jadi kita bisa mengaturnya di onCreate (dan TIDAK di onStart!).
Cukup tambahkan bendera untuk mengetahui inisialisasi pertama:

private Spinner mSpinner;
private boolean mSpinnerInitialized;

lalu di onCreate (atau onCreateView) cukup:

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;
            }
        });
Leo Droidcoder
sumber
1
Terima kasih telah menggunakan bendera ini.
Javan R.
7

Dokumen untuk widget pemintal mengatakan

Spinner tidak mendukung acara klik item.

Anda harus menggunakan setOnItemSelectedListeneruntuk menangani masalah Anda.

johndotnet
sumber
6
spinner1.setOnItemSelectedListener(
    new AdapterView.OnItemSelectedListener() {
        //add some code here
    }
);
Chiwai Chan
sumber
1
Ini tidak membahas masalah panggilan balik ini saat pemintal pertama kali diinisiasi (sehingga memicu respons yang tidak ada hubungannya dengan item yang benar-benar dipilih).
Yevgeny Simkin
4

ambil variabel global untuk pemilihan pemintal saat ini:

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>
indrajeet
sumber
4

Jika Anda menginginkan onChangedListener () yang benar. Simpan nilai awal di handler dan periksa untuk melihat apakah sudah berubah. Ini sederhana dan tidak memerlukan variabel global. Berfungsi jika Anda memiliki lebih dari satu pemintal di halaman.

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

Objek adalah teman Anda, gunakan.

fishjd
sumber
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
            }
        );
kaub0st3r
sumber
1

Ini akan bekerja menginternalisasi spinner dan findviewbyid dan gunakan ini akan bekerja

    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
        }

    });
sanjay
sumber
1

Cara terbaik apa yang saya pikir akan memiliki flagitemselected = 0;di onCreate(). Dan pada item yang dipilih kenaikan acara yaitu bendera flagitemselected++; lalu periksa

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

Saya kira ini akan membantu.

Pinakin
sumber
0

Satu trik yang saya temukan adalah meletakkan setOnItemSelectedListeners Anda di onWindowFocusChanged alih-alih onCreate. Saya belum menemukan efek samping buruk untuk melakukannya dengan cara ini, belum. Pada dasarnya, atur pendengar setelah jendela ditarik. Saya tidak yakin seberapa sering onWindowFocusChanged berjalan, tetapi cukup mudah untuk membuat diri Anda sendiri sebagai variabel kunci jika Anda mendapati itu berjalan terlalu sering.

Saya pikir Android mungkin menggunakan sistem pemrosesan berbasis pesan, dan jika Anda memasukkan semuanya ke dalam onCreate, Anda dapat mengalami situasi di mana pemintal akan diisi setelah ditarik. Jadi, pendengar Anda akan mati setelah Anda mengatur lokasi item. Ini adalah tebakan yang terdidik, tentu saja, tetapi jangan ragu untuk mengoreksi saya dalam hal ini.

Joe Plante
sumber
0

Secara default, Anda akan mendapatkan item pertama dari array pemintal melalui

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

setiap kali Anda memilih nilai dalam pemintal ini akan memberi Anda nilai yang dipilih

jika Anda menginginkan posisi item yang dipilih maka lakukanlah seperti itu

pos = spinner.getSelectedItemPosition();

dua jawaban di atas adalah untuk tanpa menerapkan pendengar

Adam Noor
sumber