Mengapa tidak menggunakan flag true / false yang sederhana? Ini cara paling sederhana untuk menyelesaikan masalah ini dan hanya membutuhkan tiga baris kode tambahan. Lihat jawaban saya di bawah ini.
Ruchir Baronia
Jawaban:
280
Tidak, kamu tidak bisa melakukannya. The onCheckedChangedmetode ini disebut langsung dari setChecked. Yang dapat Anda lakukan adalah sebagai berikut:
Bagaimana Anda melamarnya mListener? Checkboxtidak memiliki pengambil untuk ituOnCheckChangeListener
tir38
20
Yah tidak perlu downvote hanya karena Anda tidak mengerti solusinya. mListeneradalah implementasi dari OnCheckChangedListenerantarmuka, yang dibuat oleh programmer. Jawaban saya menyiratkan bahwa programmer mempertahankan referensi untuk implementasi mereka sendiri - mListener.
Shade
Apakah tidak efisien untuk mengubah pendengar jika Anda ingin menggunakan metode setChecked () berulang kali?
Ren
4
@ Ren, mengubah pendengar hanya melibatkan pengaturan properti di CheckBoxobjek. Saya tidak akan mengatakan itu tidak efisien.
Shade
Dokumen berbunyi "Dipanggil ketika tombol radio yang diperiksa telah berubah. Ketika pemilihan dihapus, checkId adalah -1". Ini benar-benar menyesatkan, seharusnya isChecked juga dilewati.
AA_PV
69
Tambahkan kode ini di dalam OnCheckedChangeListener:
if(!compoundButton.isPressed()){return;}
Ini akan membantu kami untuk mengetahui kondisi kotak centang cuaca telah diubah secara programatik atau oleh tindakan pengguna.
Ini harus ditandai sebagai solusi, berfungsi seperti pesona!
Ashwin Balani
5
Waspadalah! Ini merusak mode aksesibilitas! isPressed () tidak benar ketika dipicu oleh ketukan dua kali dari mode asisten suara.
A1m
21
Cara lain yang mungkin untuk mencapai ini adalah dengan menggunakan Kotak Centang kustom, yang akan memungkinkan Anda memilih apakah Anda ingin pendengar dipanggil atau tidak:
classCheckBox@JvmOverloadsconstructor(context:Context, attrs:AttributeSet?=null, defStyleAttr:Int=0):AppCompatCheckBox(context, attrs, defStyleAttr){privatevar listener:CompoundButton.OnCheckedChangeListener?=nulloverride fun setOnCheckedChangeListener(listener:CompoundButton.OnCheckedChangeListener?){this.listener = listenersuper.setOnCheckedChangeListener(listener)}
fun setChecked(checked:Boolean, alsoNotify:Boolean){if(!alsoNotify){super.setOnCheckedChangeListener(null)super.setChecked(checked)super.setOnCheckedChangeListener(listener)return}super.setChecked(checked)}
fun toggle(alsoNotify:Boolean){if(!alsoNotify){super.setOnCheckedChangeListener(null)super.toggle()super.setOnCheckedChangeListener(listener)}super.toggle()}}
Bagi siapa pun yang menemukan ini, satu cara sederhana untuk melakukan ini adalah dengan menggunakan tag pada kotak centang dan kemudian memeriksa tag itu pada pendengarnya (kode ada di Kotlin):
Kemudian ketika mengakses cukup atur tag ke true sebelum Anda mengatur isChecked to true ketika Anda ingin mengabaikan perubahan nilai:
checkBox.tag =true
checkBox.isChecked =true
Anda juga bisa memetakan tag ke kunci dengan menggunakan metode setTag alternatif yang membutuhkan kunci jika Anda khawatir tentang pemahaman. Tetapi jika semuanya berisi satu kelas saja, beberapa string komentar akan lebih dari cukup untuk menjelaskan apa yang terjadi.
Anda bisa menggunakan kelas SafeCheckBox ini sebagai kotak centang Anda:
publicclassSafeCheckBoxextendsAppCompatCheckBoximplementsCompoundButton.OnCheckedChangeListener{privateOnSafeCheckedListener onSafeCheckedListener;privateint mIgnoreListener = CALL_LISTENER;publicstaticfinalint IGNORE =0;publicstaticfinalint CALL_LISTENER =1;@Retention(RetentionPolicy.SOURCE)@IntDef({IGNORE, CALL_LISTENER})public@interfaceListenerMode{}publicSafeCheckBox(Context context){super(context);
init(context);}publicSafeCheckBox(Context context,AttributeSet attrs){super(context, attrs);
init(context);}publicSafeCheckBox(Context context,AttributeSet attrs,int defStyleAttr){super(context, attrs, defStyleAttr);
init(context);}/**
* @param checkState change state of the checkbox to
* @param mIgnoreListener true to ignore the listener else listener will be notified
*/publicvoid setSafeCheck(boolean checkState,@ListenerModeint mIgnoreListener){if(isChecked()== checkState)return;//already in the same state no need to fire listener. if(onSafeCheckedListener !=null){// this to avoid a bug if the user listens for the event after using this method and in that case he will miss first checkthis.mIgnoreListener = mIgnoreListener;}else{this.mIgnoreListener = CALL_LISTENER;}
setChecked(checkState);}privatevoid init(Context context){
setOnCheckedChangeListener(this);}publicOnSafeCheckedListener getOnSafeCheckedListener(){return onSafeCheckedListener;}publicvoid setOnSafeCheckedListener(OnSafeCheckedListener onSafeCheckedListener){this.onSafeCheckedListener = onSafeCheckedListener;}@Overridepublicvoid onCheckedChanged(CompoundButton buttonView,boolean isChecked){if(onSafeCheckedListener !=null)
onSafeCheckedListener.onAlwaysCalledListener(buttonView, isChecked);// this has to be called before onCheckedChangeif(onSafeCheckedListener !=null&&(mIgnoreListener == CALL_LISTENER)){
onSafeCheckedListener.onCheckedChanged(buttonView, isChecked);}
mIgnoreListener = CALL_LISTENER;}/**
* Listener that will be called when you want it to be called.
* On checked change listeners are called even when the setElementChecked is called from code. :(
*/publicinterfaceOnSafeCheckedListenerextendsOnCheckedChangeListener{void onAlwaysCalledListener(CompoundButton buttonView,boolean isChecked);}}
Maka Anda dapat menelepon: -
setSafeCheck(true,ListenerMode.IGNORE);// OnCheckedChange listener will not be notified
CompoundButtonListener checkBoxListener =newCompoundButtonListener(){@Overridepublicvoid onCheckedChanged(CompoundButton compoundButton,booleanchecked){if(isEnabled()){// Your code goes here}}};
myCheckBox.setOnCheckedChangeListener(checkBoxListener);
Pemakaian:
checkBoxListener.disable();// Some logic based on which you will modify CheckBox state// Example: myCheckBox.setChecked(true)
checkBoxListener.enable();
switch.setOnCheckedChangeListener(newCompoundButton.OnCheckedChangeListener(){@Overridepublicvoid onCheckedChanged(CompoundButton compoundButton,boolean selected){//If switch has a tag, ignore belowif(compoundButton.getTag()!=null)return;if(selected){// do something}else{// do something else}}});
Saya menggunakan ReentrantLock, dan menguncinya setiap kali saya mengatur isChecked:
// lock when isChecked is being set programmatically
val isBeingProgrammaticallySet =ReentrantLock()// set isChecked programmatically
isBeingProgrammaticallySet.withLock(){
checkbox.isChecked =true}// do something only when preference is modified by user
checkbox.setOnCheckedChangeListener(){
_,isChecked ->if(isBeingProgrammaticallySet.isHeldByCurrentThread.not()){// do it}}
Saya menemukan semua jawaban di atas terlalu rumit. Mengapa tidak membuat bendera sendiri dengan boolean sederhana?
Cukup gunakan sistem bendera sederhana dengan boolean. Buat boolean noListener. Kapan pun Anda ingin menghidupkan / mematikan sakelar tanpa menjalankan kode apa pun (dalam contoh ini, direpresentasikan sebagai runListenerCode(), cukup setel noListener=truesebelum memanggilswitch.setChecked(false/true)
switch.setOnCheckedChangeListener(newCompoundButton.OnCheckedChangeListener(){@Overridepublicvoid onCheckedChanged(CompoundButton compoundButton,boolean selected){if(!noListener){//If we want to run our code like usual
runListenerCode();}else{//If we simply want the switch to turn off
noListener =false;}});
Solusi yang sangat sederhana menggunakan flag sederhana. Pada akhirnya, kami menetapkan noListener=falsesekali lagi sehingga kode kami terus berfungsi. Semoga ini membantu!
Saya tidak benar-benar ingin harus melewati pendengar di setiap kali kami mengatur diperiksa berubah, atau menggunakan enabledsebagai cara untuk menentukan apakah kita harus menetapkan nilai (apa yang terjadi dalam kasus kami telah menonaktifkan saklar ketika mengatur nilai ?)
Alih-alih, saya menggunakan tag dengan id dan beberapa metode ekstensi yang dapat Anda hubungi:
fun CompoundButton.setOnCheckedWithoutCallingChangeListener(
listener:(view:CompoundButton,checked:Boolean)->Unit){
setOnCheckedChangeListener { view,checked->if(view.getTag(R.id.compound_button_checked_changed_listener_disabled)!=true){
listener(view,checked)}}this.setTag(R.id.compound_button_enabled_checked_change_supported,true)}
fun CompoundButton.setCheckedWithoutCallingListener(checked:Boolean){
check(this.getTag(R.id.compound_button_enabled_checked_change_supported)==true){"Must set listener using `setOnCheckedWithoutCallingChangeListener` to call this method"}
setTag(R.id.compound_button_checked_changed_listener_disabled,true)
isChecked =checked
setTag(R.id.compound_button_checked_changed_listener_disabled,false)}
Sekarang Anda dapat menelepon setCheckedWithoutCallingListener(bool)dan itu akan memberlakukan penggunaan pendengar yang benar.
Anda juga masih dapat menelepon setChecked(bool)untuk memecat pendengar jika Anda masih membutuhkannya
Dapat bekerja hingga dev mengubah nama bidang atau, misalnya, menarik metode "isChecked" dalam hierarki ... atau melakukan refactoring lain ... Setidaknya tambahkan sesuatu sepertiif(Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN){ /* do reflection */}
aeracode
Gagasan yang salah adalah mendorong untuk memutus API dan menggali internal. Setiap perubahan pada implementasi akan menyebabkan aplikasi gagal.
mspanc
0
Solusi saya ditulis dalam java berdasarkan jawaban @ Chris:
Jawaban:
Tidak, kamu tidak bisa melakukannya. The
onCheckedChanged
metode ini disebut langsung darisetChecked
. Yang dapat Anda lakukan adalah sebagai berikut:Lihat sumber Kotak Centang , dan penerapan
setChecked
:sumber
mListener
?Checkbox
tidak memiliki pengambil untuk ituOnCheckChangeListener
mListener
adalah implementasi dariOnCheckChangedListener
antarmuka, yang dibuat oleh programmer. Jawaban saya menyiratkan bahwa programmer mempertahankan referensi untuk implementasi mereka sendiri -mListener
.CheckBox
objek. Saya tidak akan mengatakan itu tidak efisien.Tambahkan kode ini di dalam OnCheckedChangeListener:
Ini akan membantu kami untuk mengetahui kondisi kotak centang cuaca telah diubah secara programatik atau oleh tindakan pengguna.
sumber
Cara lain yang mungkin untuk mencapai ini adalah dengan menggunakan Kotak Centang kustom, yang akan memungkinkan Anda memilih apakah Anda ingin pendengar dipanggil atau tidak:
Versi Kotlin, jika Anda lebih suka:
penggunaan sampel:
sumber
Anda hanya menggunakan setonclickListener, ini akan berfungsi dengan baik dan ini adalah metode yang sangat sederhana, terima kasih :)
sumber
Menggunakan ekstensi Kotlin dengan jawaban @Shade:
sumber
Bagi siapa pun yang menemukan ini, satu cara sederhana untuk melakukan ini adalah dengan menggunakan tag pada kotak centang dan kemudian memeriksa tag itu pada pendengarnya (kode ada di Kotlin):
Kemudian ketika mengakses cukup atur tag ke true sebelum Anda mengatur isChecked to true ketika Anda ingin mengabaikan perubahan nilai:
Anda juga bisa memetakan tag ke kunci dengan menggunakan metode setTag alternatif yang membutuhkan kunci jika Anda khawatir tentang pemahaman. Tetapi jika semuanya berisi satu kelas saja, beberapa string komentar akan lebih dari cukup untuk menjelaskan apa yang terjadi.
sumber
Anda bisa menggunakan kelas SafeCheckBox ini sebagai kotak centang Anda:
Maka Anda dapat menelepon: -
setSafeCheck(true,ListenerMode.IGNORE);// OnCheckedChange listener will not be notified
sumber
Setel nol ke changeListener sebelum memeriksa tombol radio. Anda dapat mengatur pendengar lagi setelah memeriksa tombol radio.
sumber
Interpretasi saya yang saya pikir paling mudah
Semoga bermanfaat)
Gunakan
gunakan akan memicu
setChecked(boolean)
fungsiitu saja
KOTLIN
sumber
Ini adalah solusi sederhana yang saya gunakan:
Tentukan pendengar khusus:
Inisialisasi:
Pemakaian:
sumber
Bagaimana dengan ini. Coba gunakan Tag dalam Tampilan
dan
sumber
Saya menggunakan
ReentrantLock
, dan menguncinya setiap kali saya mengaturisChecked
:sumber
Cukup gunakan sistem bendera sederhana dengan boolean. Buat
boolean noListener
. Kapan pun Anda ingin menghidupkan / mematikan sakelar tanpa menjalankan kode apa pun (dalam contoh ini, direpresentasikan sebagairunListenerCode()
, cukup setelnoListener=true
sebelum memanggilswitch.setChecked(false/true)
Solusi yang sangat sederhana menggunakan flag sederhana. Pada akhirnya, kami menetapkan
noListener=false
sekali lagi sehingga kode kami terus berfungsi. Semoga ini membantu!sumber
Coba yang ini seharusnya bekerja untuk Anda! Anda dapat menggunakan ini dengan firebase juga!
Untuk mendapatkan data berbasis firebase! Gunakan ini!
Setelah itu ketika pengguna melakukan sesuatu!
sumber
Saya tidak benar-benar ingin harus melewati pendengar di setiap kali kami mengatur diperiksa berubah, atau menggunakan
enabled
sebagai cara untuk menentukan apakah kita harus menetapkan nilai (apa yang terjadi dalam kasus kami telah menonaktifkan saklar ketika mengatur nilai ?)Alih-alih, saya menggunakan tag dengan id dan beberapa metode ekstensi yang dapat Anda hubungi:
Sekarang Anda dapat menelepon
setCheckedWithoutCallingListener(bool)
dan itu akan memberlakukan penggunaan pendengar yang benar.Anda juga masih dapat menelepon
setChecked(bool)
untuk memecat pendengar jika Anda masih membutuhkannyasumber
Saya kira menggunakan refleksi adalah satu-satunya cara. Sesuatu seperti ini:
sumber
if(Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN){ /* do reflection */}
Solusi saya ditulis dalam java berdasarkan jawaban @ Chris:
2 kotak centang dan selalu satu akan diperiksa (satu harus awalnya harus diperiksa). Menyetel tag ke blok yang benar di pendengar yang diubah
sumber
sumber