Android 更改复选框值而不触发onCheckChanged
我已经为我的Android 更改复选框值而不触发onCheckChanged,android,checkbox,Android,Checkbox,我已经为我的复选框 我能打电话给你吗 checkbox.setChecked(false); 如果不触发onCheckedChanged的否,则无法执行此操作。直接从setChecked调用onCheckedChanged方法。您可以执行以下操作: mCheck.setOnCheckedChangeListener (null); mCheck.setChecked (false); mCheck.setOnCheckedChangeListener (mListener); 请参阅,以及s
复选框
我能打电话给你吗
checkbox.setChecked(false);
如果不触发onCheckedChanged的否,则无法执行此操作。直接从setChecked
调用onCheckedChanged
方法。您可以执行以下操作:
mCheck.setOnCheckedChangeListener (null);
mCheck.setChecked (false);
mCheck.setOnCheckedChangeListener (mListener);
请参阅,以及setChecked
的实现:
public void setChecked(boolean checked) {
if (mChecked != checked) {
mChecked = checked;
refreshDrawableState();
// Avoid infinite recursions if setChecked() is called from a listener
if (mBroadcasting) {
return;
}
mBroadcasting = true;
if (mOnCheckedChangeListener != null) {
mOnCheckedChangeListener.onCheckedChanged(this, mChecked);
}
if (mOnCheckedChangeWidgetListener != null) {
mOnCheckedChangeWidgetListener.onCheckedChanged(this, mChecked);
}
mBroadcasting = false;
}
}
我想使用反射是唯一的方法。大概是这样的:
CheckBox cb = (CheckBox) findViewById(R.id.checkBox1);
try {
Field field = CompoundButton.class.getDeclaredField("mChecked");
field.setAccessible(true);
field.set(cb, cb.isChecked());
cb.refreshDrawableState();
cb.invalidate();
} catch (Exception e) {
e.printStackTrace();
}
使用simply setonclickListener,效果会很好,这是一种非常简单的方法,谢谢:)实现这一点的另一种可能方法是使用自定义复选框,它将让您选择是否要调用侦听器:
public class CheckBox extends AppCompatCheckBox {
private OnCheckedChangeListener mListener;
public CheckBox(final Context context) {
super(context);
}
public CheckBox(final Context context, final AttributeSet attrs) {
super(context, attrs);
}
public CheckBox(final Context context, final AttributeSet attrs, final int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public void setOnCheckedChangeListener(final OnCheckedChangeListener listener) {
mListener = listener;
super.setOnCheckedChangeListener(listener);
}
public void setChecked(final boolean checked, final boolean alsoNotify) {
if (!alsoNotify) {
super.setOnCheckedChangeListener(null);
super.setChecked(checked);
super.setOnCheckedChangeListener(mListener);
return;
}
super.setChecked(checked);
}
public void toggle(boolean alsoNotify) {
if (!alsoNotify) {
super.setOnCheckedChangeListener(null);
super.toggle();
super.setOnCheckedChangeListener(mListener);
return;
}
super.toggle();
}
}
Kotlin版本,如果您愿意:
class CheckBox @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : AppCompatCheckBox(context, attrs, defStyleAttr) {
private var listener: CompoundButton.OnCheckedChangeListener? = null
override fun setOnCheckedChangeListener(listener: CompoundButton.OnCheckedChangeListener?) {
this.listener = listener
super.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)
return
}
super.toggle()
}
}
示例用法:
checkBox.setChecked(true,false);
您可以使用此SafeCheckBox类作为复选框:
public class SafeCheckBox extends AppCompatCheckBox implements CompoundButton.OnCheckedChangeListener {
private OnSafeCheckedListener onSafeCheckedListener;
private int mIgnoreListener = CALL_LISTENER;
public static final int IGNORE = 0;
public static final int CALL_LISTENER = 1;
@Retention(RetentionPolicy.SOURCE)
@IntDef({IGNORE, CALL_LISTENER})
public @interface ListenerMode {
}
public SafeCheckBox(Context context) {
super(context);
init(context);
}
public SafeCheckBox(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public SafeCheckBox(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
*/
public void setSafeCheck(boolean checkState, @ListenerMode int 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 check
this.mIgnoreListener = mIgnoreListener;
} else {
this.mIgnoreListener = CALL_LISTENER;
}
setChecked(checkState);
}
private void init(Context context) {
setOnCheckedChangeListener(this);
}
public OnSafeCheckedListener getOnSafeCheckedListener() {
return onSafeCheckedListener;
}
public void setOnSafeCheckedListener(OnSafeCheckedListener onSafeCheckedListener) {
this.onSafeCheckedListener = onSafeCheckedListener;
}
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (onSafeCheckedListener != null)
onSafeCheckedListener.onAlwaysCalledListener(buttonView, isChecked);// this has to be called before onCheckedChange
if (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. :(
*/
public interface OnSafeCheckedListener extends OnCheckedChangeListener {
void onAlwaysCalledListener(CompoundButton buttonView, boolean isChecked);
}
}
- 然后你可以打电话:-
setSafeCheck(true,ListenerMode.IGNORE);//OnCheckedChange监听器将不会收到通知
使用Kotlin的扩展和@Shade answer:
fun CompoundButton.setCustomChecked(value: Boolean,listener: CompoundButton.OnCheckedChangeListener) {
setOnCheckedChangeListener(null)
isChecked = value
setOnCheckedChangeListener(listener)
}
对于任何偶然发现这一点的人,一种更简单的方法是在复选框上使用标记,然后在其侦听器上检查该标记(代码在Kotlin中):
然后,在访问时,如果要忽略值更改,请先将标记设置为true,然后再将isChecked设置为true:
checkBox.tag = true
checkBox.isChecked = true
如果担心可理解性,还可以使用需要密钥的替代setTag方法将标记映射到密钥。但是,如果它全部包含在一个类中,那么几个注释字符串就足以解释发生了什么。在选中单选按钮之前,将null设置为changeListener。您可以在选中单选按钮后再次设置侦听器
radioGroup.setOnCheckedChangeListener(null);
radioGroup.check(R.id.radioButton);
radioGroup.setOnCheckedChangeListener(new
RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup radioGroup, @IdRes int i) {
}
});
我的解决方案是基于@Chris answer用java编写的:
chkParent.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if(buttonView.getTag() != null){
buttonView.setTag(null);
return;
}
if(isChecked){
chkChild.setTag(true);
chkChild.setChecked(false);
}
else{
chkParent.setChecked(true);
}
}
});
chkChild.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if(buttonView.getTag() != null){
buttonView.setTag(null);
return;
}
if(isChecked){
chkParent.setTag(true);
chkParent.setChecked(false);
}
else{
chkChild.setChecked(true);
}
}
});
2个复选框,并且始终选中一个复选框(但一开始必须选中一个)。将tag设置为true会在检查更改的侦听器时阻塞。我认为最简单的解释
(可能有帮助)
使用它
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean on) {
if (((ProgrammableSwitchCompat) compoundButton).isCheckedProgrammatically) {
return;
}
//...
((ProgrammableSwitchCompat) compoundButton).setCheckedProgrammatically(true);
//...
((ProgrammableSwitchCompat) compoundButton).setCheckedProgrammatically(false);
//...
}
使用将触发setChecked(布尔)
函数
就这些
KOTLIN
class MyCheckBox @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = R.attr.switchStyle
) : AppCompatCheckBox(context, attrs, defStyleAttr) {
var programmatically = false
override fun setChecked(checked: Boolean) {
programmatically = false
super.setChecked(checked)
}
fun setCheckedProgrammatically(checked: Boolean) {
programmatically = true
super.setChecked(checked)
}
}
这是我使用的一个简单解决方案:
定义自定义侦听器:
class CompoundButtonListener implements CompoundButton.OnCheckedChangeListener {
boolean enabled = false;
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
}
void enable() {
enabled = true;
}
void disable() {
enabled = false;
}
boolean isEnabled() {
return enabled;
}
}
CompoundButtonListener checkBoxListener = new CompoundButtonListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
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();
// 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
}
}
初始化:
class CompoundButtonListener implements CompoundButton.OnCheckedChangeListener {
boolean enabled = false;
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
}
void enable() {
enabled = true;
}
void disable() {
enabled = false;
}
boolean isEnabled() {
return enabled;
}
}
CompoundButtonListener checkBoxListener = new CompoundButtonListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
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();
// 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
}
}
用法:
class CompoundButtonListener implements CompoundButton.OnCheckedChangeListener {
boolean enabled = false;
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
}
void enable() {
enabled = true;
}
void disable() {
enabled = false;
}
boolean isEnabled() {
return enabled;
}
}
CompoundButtonListener checkBoxListener = new CompoundButtonListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
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();
// 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
}
}
这个怎么样。
尝试在视图中使用标记
mCheck.setTag("ignore");
mCheck.setChecked(true);
mCheck.setTag(null);
及
我发现上面所有的答案都太复杂了。为什么不用简单的布尔值创建自己的标志呢
只需使用带有布尔值的简单标志系统。创建布尔noListener
。每当您想在不运行任何代码的情况下打开/关闭开关时(在本例中,表示为runListenerCode()
),只需在调用switch.setChecked(false/true)
使用简单标志的非常简单的解决方案。最后,我们再次设置noListener=false
,以便代码继续工作。希望这有帮助!在OnCheckedChangeListener中添加此代码:
if(!compoundButton.isPressed()) {
return;
}
这将帮助我们确定复选框状态是通过编程或用户操作更改的。我使用了一个可重入锁定
,并在设置时锁定它:
public void setChecked(boolean checked) {
if (mChecked != checked) {
mChecked = checked;
refreshDrawableState();
// Avoid infinite recursions if setChecked() is called from a listener
if (mBroadcasting) {
return;
}
mBroadcasting = true;
if (mOnCheckedChangeListener != null) {
mOnCheckedChangeListener.onCheckedChanged(this, mChecked);
}
if (mOnCheckedChangeWidgetListener != null) {
mOnCheckedChangeWidgetListener.onCheckedChanged(this, mChecked);
}
mBroadcasting = false;
}
}
Kotlin:
class CompoundButtonListener implements CompoundButton.OnCheckedChangeListener {
boolean enabled = false;
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
}
void enable() {
enabled = true;
}
void disable() {
enabled = false;
}
boolean isEnabled() {
return enabled;
}
}
CompoundButtonListener checkBoxListener = new CompoundButtonListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
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();
// 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
}
}
试试这个吧!你也可以用firebase
要获取firebase数据,请使用此
databaseReference.child(user.getPhoneNumber()).child("Reqs").addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
SharedPreferences prefs = mContext.getSharedPreferences("uinfo", MODE_PRIVATE);
String pno = prefs.getString("username", "No name defined");
if(dataSnapshot.child(pno).getValue(String.class).equals("acc")){
holder.acc.setChecked(true);
}else{
holder.acc.setChecked(false);
}
}
@Override
public void onCancelled(DatabaseError databaseError) {
// Getting Post failed, log a message
Log.w("dfs", "loadPost:onCancelled", databaseError.toException());
// ...
}
});
之后,当用户做某事
holder.acc.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if(isChecked) {
if(buttonView.isPressed()) {
//your code
}
}
else {
if(buttonView.isPressed()) {
//your code
}
}
}
});
我真的不想每次设置checked change时都通过侦听器,也不想使用enabled
作为确定是否应该设置值的方法(如果设置值时已经禁用了开关,会发生什么情况?)
相反,我使用带有id的标记和两个可调用的扩展方法:
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)
}
现在您可以调用setchecked而不调用listener(bool)
,它将强制执行正确的侦听器用法
如果仍然需要,您也可以调用setChecked(bool)
来启动侦听器非常简单,您只需在setoncheckedchangelister中选中isPressed
科特林
switch.setOnCheckedChangeListener { buttonView, isChecked ->
when {
buttonView.isPressed -> {
foo(isChecked)
}
}
下面是一个非常容易使用的标签技术版本
用法:
// Pass true to enable bypassing of the listener
button.setOnCheckedChangedListener(true) { _, isChecked ->
// your usual code
}
// Use extension function to set the value and bypass the listener
button.setCheckedSilently(true)
它通过几个实用程序扩展功能完成:
inline fun CompoundButton.setOnCheckedChangeListener(canBypass: Boolean, crossinline listener: (CompoundButton, Boolean) -> Unit) {
if (canBypass) {
setOnCheckedChangeListener { view, isChecked ->
if (view.tag != ListenerBypass) {
listener(view, isChecked)
}
}
} else {
setOnCheckedChangeListener { view, isChecked -> listener(view, isChecked) }
}
}
fun CompoundButton.setCheckedSilently(isChecked: Boolean) {
val previousTag = tag
tag = ListenerBypass
this.isChecked = isChecked
tag = previousTag
}
object ListenerBypass
您打算如何获取mListener
?Checkbox
的OnCheckChangedListener
没有一个getter,您不需要因为不理解解决方案就否决投票。mListener
是程序员创建的OnCheckChangedListener
接口的实现。我的答案意味着程序员维护了对他们自己实现的引用-mListener
。如果要使用setChecked()函数,更改侦听器是否效率低下方法重复?@Ren,更改侦听器只涉及复选框
对象中的属性设置。我不会说这是低效的。文档显示“当选中的单选按钮已更改时调用。当清除选择时,checkedId为-1”。这确实有误导性,它应该也传递isChecked。当用户滑动开关时,不会调用onClick()。实际上,这样做会在用户拖动切换时使您没有处理程序。那么如何获得isChecked值,即true或false?可能会一直工作,直到开发人员更改字段名,或者,例如,调出“isChecked”方法…或者进行另一次重构…至少添加类似于if的内容(Build.VERSION.SDK_INT鼓励破坏API并深入内部是错误的想法。对实现的任何更改都会导致应用程序失败。为什么不使用简单的真/假标志呢?这是解决此问题的最简单方法,只需要三行额外代码。请参阅下面我的答案。请注意!这会破坏可访问性m当ode!isPressed()由