【问题标题】:onCheckedChanged called automaticallyonCheckedChanged 自动调用
【发布时间】:2015-02-22 20:31:43
【问题描述】:

我在 recyclerview 中有一个开关,从 DB 检索数据后,数据会显示在 recyclerview 中。当 recyclerview 打开时,我读取 DB,如果 DB 中的字段为“Y”,则启用开关,否则禁用开关。 现在的问题是 onCheckedchanged 监听器也被调用了,我希望只有在用户手动设置开关时才调用 onCheckedChanged。

在打开下面的recyclerview时执行:

holder.enabledisable.setChecked(messengerRecord.get_is_valid().equalsIgnoreCase("Y"));

ViewHolder 类:

public class viewHolder extends RecyclerView.ViewHolder implements CompoundButton.OnCheckedChangeListener{
public SwitchCompat enabledisable;
 public viewHolder(View v) {
            enabledisable = (SwitchCompat) v.findViewById(R.id.enabledisable);
            enabledisable.setOnCheckedChangeListener(this);
...................................
...................................

刚刚打开recyclerView时调用的OncheckedChanged方法:

@Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            Log.v("ranjith","called oncheckedchanged");
            MessengerRecord rec;
            rec = dbHelper.getRecord(descview.getText().toString());
            switch (buttonView.getId()) {
                case R.id.enabledisable:
                    if (isChecked) {
                        rec.set_is_valid("Y");
                        dbHelper.updateRecord(rec);
                     }
}

在布局文件中:

<android.support.v7.widget.SwitchCompat
    android:layout_marginRight="16dp"
    android:layout_marginEnd="16dp"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:focusable="false"
    android:id="@+id/enabledisable"
    android:layout_alignRight="@+id/textview_to"
    android:layout_alignEnd="@+id/textview_to"
    android:layout_alignParentRight="true"
    android:layout_alignParentEnd="true"/>

【问题讨论】:

    标签: android android-recyclerview oncheckedchanged android-switch switchcompat


    【解决方案1】:

    奇怪的是,我们所有人都有这个问题,但谷歌却没有对这个简单问题的官方回答。

    检查最简单:

    buttonView.isPressed()
    

    如果为真,则表示用户点击了视图。

    不需要全局变量。

    希望这会有所帮助。

    【讨论】:

    • 这绝对有效。但是,如果用户滑动开关,会有什么事件吗?在这种情况下,如果使用的是滑动开关,这是行不通的。
    • 感谢这个简单而出色的解决方案。这也可以与RadioButton 一起使用。对于RadioGroup,我写了this answer
    • 感谢@Surfian 的提及 :),我很高兴这也适用于 RadioButton
    • 如果您快速滑动 Switch,该解决方案将不起作用。愚蠢的谷歌
    • 您可以通过实现 OnClickListener 并使用 SwitchCompat 的 isChecked() 方法进行检查来手动处理,不需要使用 onCheckedChangeListener。
    【解决方案2】:

    我最终使用了 SwitchCompat 的这个子类来避免这个问题。这样,我在使用此类的地方就不需要样板代码。 每当您需要更改已检查而不触发侦听器时,请使用setCheckedSilent 而不是setChecked

    import android.content.Context;
    import android.os.Parcelable;
    import android.support.v7.widget.SwitchCompat;
    import android.util.AttributeSet;
    
    /**
     * Created by emanuel on 30/5/16.
     */
    public class Switch extends SwitchCompat {
    
        private OnCheckedChangeListener listener;
    
        public Switch(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        @Override
        public void setOnCheckedChangeListener(OnCheckedChangeListener listener) {
            this.listener = listener;
            super.setOnCheckedChangeListener(listener);
        }
    
        @Override
        public void onRestoreInstanceState(Parcelable state) {
            super.setOnCheckedChangeListener(null);
            super.onRestoreInstanceState(state);
            super.setOnCheckedChangeListener(listener);
        }
    
        public void setCheckedSilent(boolean checked) {
            super.setOnCheckedChangeListener(null);
            super.setChecked(checked);
            super.setOnCheckedChangeListener(listener);
        }
    }
    

    onRestoreInstanceState 也触发了侦听,当在 onViewCreated 方法中设置时,您将返回到前一个片段。 希望它对你有用!

    【讨论】:

      【解决方案3】:

      试试这个

      @Override
      public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
      
              if (buttonView.isPressed()) {
                ... //returns true, if user clicks the switch button        
              }}
      

      【讨论】:

      • 如果滑动速度非常快,这将不起作用。
      • 从事 Android 开发已有 10 多年,从不知道这个技巧,谢谢!
      【解决方案4】:

      由于RecyclerView 是回收视图,因此在为新项目的Switch 设置检查值时可以触发先前附加的OnCheckedChangeListener

      将新数据绑定到项目时:

         switch.setOnCheckedChangeListener(null) // remove any existing listener from recycled view
         switch.isChecked = [true/false] // will no longer trigger any callback to listener
         switch.setOnCheckedChangeListener { btnView, isChecked ->
             // do exiting stuff
         }
      

      【讨论】:

      • 非常感谢您发布此消息。我在Recyclerview 中有多个Switch 视图,并且恰好遇到了这个问题。删除 onBind() 中的所有现有侦听器首先解决了我的问题。
      【解决方案5】:

      这对我有用:

       boolean selected = preferences.isChecked();
              yourCheckBox.setOnCheckedChangeListener(new 
                  CompoundButton.OnCheckedChangeListener() {
                      @Override
                      public void onCheckedChanged(CompoundButton buttonView, 
                  boolean isChecked) {
                          if (buttonView.isPressed()) {
                     preferences.setChecked(isChecked);
                          } else {
                              yourCheckBox.setChecked(selected);
                          }
                      }
                  });
      

      【讨论】:

      • 如果滑动速度非常快,这将不起作用。
      【解决方案6】:

      使用全局布尔变量,当从 DB 读取数据时将其设置为“true”,并在 onCheckChange 中的 check(if) 后再次将其设置为“false”。在 onCheckChange 方法的第一个检查这个变量是否为 false 执行代码 else return(这个变量的默认值必须是 false ) ;

      @Override
         public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
           if(!isSourceDB){ 
      
             Log.v("ranjith","called oncheckedchanged");
              MessengerRecord rec;
              rec = dbHelper.getRecord(descview.getText().toString());
              switch (buttonView.getId()) {
                  case R.id.enabledisable:
                      if (isChecked) {
                          rec.set_is_valid("Y");
                          dbHelper.updateRecord(rec);
      
                }
          }//end if
        isSourceDB = false; }// end oncheckedchange
      

      【讨论】:

      • 这似乎是一种解决方法。我在 android 中寻找一个功能,它仅在用户单击时调用 oncheckedchanged(即焦点被接收)。但它有效。我投票赞成。
      • @Ranjith:当单击 Switch 时,第一次调用 toggle() 方法,并在 toggle 方法中调用 setchecked() 方法。所以你应该在切换方法中插入上述代码,而不是在 checkchanged 上。顺便说一句,如果你只想写 onCheckChange() 你应该写一个只改变开关的GUI状态并在从数据库读取数据时调用它的方法。
      【解决方案7】:

      我在 ViewPager 屏幕的片段中遇到了同样的问题。当我们在fragment之间切换时,onCheckedChanged Listener会被一次又一次的调用。

      如果有人还在寻找这个问题,请尝试一下。

      @Override
          public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
      
                  if (buttonView.isInTouchMode()) {
                    ... //Your code will come here.         
                  }
      }
      

      【讨论】:

        【解决方案8】:

        Kotlin 开发者:

            checkboxXYZ.setOnCheckedChangeListener { btnView, isChecked ->
                if (btnView.isPressed) {
        
                }
            }
        

        【讨论】:

          【解决方案9】:

          如果您正在更改适配器中的状态,那么

             holder.rawManageDriverLayoutBinding.rawManageDriverSwitch.setOnCheckedChangeListener(null);
          

          setOnCheckedChangeListener之前。

          【讨论】:

            【解决方案10】:

            唯一的解决方案是在监听器中使用方法 isPressed()

            【讨论】:

              猜你喜欢
              • 2014-03-21
              • 2012-03-16
              • 1970-01-01
              • 1970-01-01
              • 2018-05-07
              • 2012-08-27
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多