Почему бы просто не использовать простой флаг true / false? Это самый простой способ решить эту проблему, и он занимает всего три строки дополнительного кода. Смотрите мой ответ ниже.
Ручир Барония
Ответы:
280
Нет, ты не можешь это сделать. onCheckedChangedМетод вызывается непосредственно из setChecked. Что вы можете сделать, это следующее:
Как вы предлагаете получить mListener? Checkboxне имеет добытчика для егоOnCheckChangeListener
tir38
20
Ну, нет необходимости понижать голосование просто потому, что вы не понимаете решение. mListenerявляется реализацией OnCheckChangedListenerинтерфейса, который был создан программистом. Мой ответ подразумевает, что программист сохранил ссылку на собственную реализацию - mListener.
тень
Было бы неэффективно менять слушателя, если вы хотите использовать метод setChecked () многократно?
Рен
4
@Ren, изменение слушателя включает только установку свойства в CheckBoxобъекте. Я бы не сказал, что это неэффективно.
тень
Документ гласит: «Вызывается, когда выбранная кнопка-переключатель изменилась. Когда выбор очищен, значение параметра idI равно -1». Это действительно вводит в заблуждение, также должен пройти isChecked.
AA_PV
69
Добавьте этот код внутри OnCheckedChangeListener:
if(!compoundButton.isPressed()){return;}
Это поможет нам выяснить, было ли состояние checkBox для погоды изменено программно или в результате действий пользователя.
Это должно быть отмечено как решение, работает как шарм!
Эшвин Балани
5
быть в курсе! Это нарушает режим доступности! isPressed () не соответствует действительности, когда он вызывается двойным нажатием в режиме голосового помощника.
A1
21
Другой возможный способ добиться этого - использовать специальный CheckBox, который позволит вам выбрать, хотите ли вы, чтобы вызывался слушатель, или нет:
Для любого, кто сталкивается с этим, один простой способ сделать это - просто использовать тег на флажке, а затем проверить этот тег на своем слушателе (код на Kotlin):
Затем при доступе просто установите для тега значение true, прежде чем установить isChecked в значение true, если хотите игнорировать изменение значения:
checkBox.tag =true
checkBox.isChecked =true
Вы также можете сопоставить тег с ключом, используя альтернативный метод setTag, который требует ключ, если вас беспокоит понятность. Но если все это содержится в одном классе, нескольких строк комментариев будет более чем достаточно, чтобы объяснить, что происходит.
Вы можете использовать этот класс SafeCheckBox в качестве вашего флажка:
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);}}
Тогда вы могли бы позвонить:
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);
Использование:
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}}});
Я использовал ReentrantLock, и блокирую это всякий раз, когда я устанавливаю 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}}
Я нашел все вышеупомянутые ответы слишком сложными. Почему бы просто не создать свой собственный флаг с простым логическим значением?
Просто используйте простую систему флагов с логическим значением. Создать boolean noListener. Всякий раз, когда вы хотите включить / выключить ваш коммутатор без запуска какого-либо кода (в этом примере, представленного как runListenerCode(), просто установите noListener=trueперед вызовомswitch.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;}});
Очень простое решение с использованием простых флагов. В конце мы noListener=falseснова установили, чтобы наш код продолжал работать. Надеюсь это поможет!
Я на самом деле не хотел, чтобы мне приходилось передавать слушателя каждый раз, когда мы устанавливали проверенные изменения, ни использовать enabled приходилось в качестве способа определения, следует ли нам устанавливать значение (что происходит в случае, если у нас уже отключен переключатель при установке значения ?)
Вместо этого я использую теги с идентификатором и несколько методов расширения, которые вы можете вызвать:
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)}
Теперь вы можете позвонить, setCheckedWithoutCallingListener(bool)и это обеспечит правильное использование слушателя.
Вы также можете позвонить, setChecked(bool)чтобы уволить слушателя, если он вам все еще нужен
Может работать до тех пор, пока разработчики не изменят имя поля или, например, не вызовут метод isChecked в иерархии ... или не выполнят другой рефакторинг ... По крайней мере, добавьте что-то вродеif(Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN){ /* do reflection */}
aeracode
Неправильно предлагать взламывать API и копаться во внутренностях. Любое изменение в реализации приведет к сбою приложений.
Mspanc
0
Мое решение написано в Java на основе ответа @Chris:
Ответы:
Нет, ты не можешь это сделать.
onCheckedChanged
Метод вызывается непосредственно изsetChecked
. Что вы можете сделать, это следующее:Посмотрите источник CheckBox и реализацию
setChecked
:источник
mListener
?Checkbox
не имеет добытчика для егоOnCheckChangeListener
mListener
является реализациейOnCheckChangedListener
интерфейса, который был создан программистом. Мой ответ подразумевает, что программист сохранил ссылку на собственную реализацию -mListener
.CheckBox
объекте. Я бы не сказал, что это неэффективно.Добавьте этот код внутри OnCheckedChangeListener:
Это поможет нам выяснить, было ли состояние checkBox для погоды изменено программно или в результате действий пользователя.
источник
Другой возможный способ добиться этого - использовать специальный CheckBox, который позволит вам выбрать, хотите ли вы, чтобы вызывался слушатель, или нет:
Версия Kotlin, если вы предпочитаете:
пример использования:
источник
вы используете просто setonclickListener, он будет работать нормально, и это очень простой метод, спасибо :)
источник
Используя расширения Kotlin с ответом @Shade:
источник
Для любого, кто сталкивается с этим, один простой способ сделать это - просто использовать тег на флажке, а затем проверить этот тег на своем слушателе (код на Kotlin):
Затем при доступе просто установите для тега значение true, прежде чем установить isChecked в значение true, если хотите игнорировать изменение значения:
Вы также можете сопоставить тег с ключом, используя альтернативный метод setTag, который требует ключ, если вас беспокоит понятность. Но если все это содержится в одном классе, нескольких строк комментариев будет более чем достаточно, чтобы объяснить, что происходит.
источник
Вы можете использовать этот класс SafeCheckBox в качестве вашего флажка:
Тогда вы могли бы позвонить:
setSafeCheck(true,ListenerMode.IGNORE);// OnCheckedChange listener will not be notified
источник
Установите null на changeListener перед проверкой переключателя. Вы можете установить слушателя снова после проверки переключателя.
источник
Моя интерпретация, которую я считаю самой простой,
может быть полезной)
используй это
использование вызовет
setChecked(boolean)
функцию,которая все
Котлин
источник
Это простое решение, которое я использовал:
Определить пользовательский слушатель:
Инициализация:
Использование:
источник
Как насчет этого. Попробуйте использовать тег в представлении
и
источник
Я использовал
ReentrantLock
, и блокирую это всякий раз, когда я устанавливаюisChecked
:источник
Просто используйте простую систему флагов с логическим значением. Создать
boolean noListener
. Всякий раз, когда вы хотите включить / выключить ваш коммутатор без запуска какого-либо кода (в этом примере, представленного какrunListenerCode()
, просто установитеnoListener=true
перед вызовомswitch.setChecked(false/true)
Очень простое решение с использованием простых флагов. В конце мы
noListener=false
снова установили, чтобы наш код продолжал работать. Надеюсь это поможет!источник
Попробуйте это должно работать для вас! Вы можете использовать это с Firebase также!
Для получения базы данных! Использовать это!
После этого когда пользователь что-то сделает!
источник
Я на самом деле не хотел, чтобы мне приходилось передавать слушателя каждый раз, когда мы устанавливали проверенные изменения, ни использовать
enabled
приходилось в качестве способа определения, следует ли нам устанавливать значение (что происходит в случае, если у нас уже отключен переключатель при установке значения ?)Вместо этого я использую теги с идентификатором и несколько методов расширения, которые вы можете вызвать:
Теперь вы можете позвонить,
setCheckedWithoutCallingListener(bool)
и это обеспечит правильное использование слушателя.Вы также можете позвонить,
setChecked(bool)
чтобы уволить слушателя, если он вам все еще нуженисточник
Я думаю, что использование отражения является единственным способом. Что-то вроде этого:
источник
if(Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN){ /* do reflection */}
Мое решение написано в Java на основе ответа @Chris:
2 флажка и всегда один будет отмечен (хотя один должен быть проверен изначально). Установка тега в истинные блоки на прослушивателе CheckedChanged.
источник
источник