【问题标题】:Facing issue in setOnCheckedChangeListener position value in RecyclerView AndroidRecyclerView Android中的setOnCheckedChangeListener位置值面临问题
【发布时间】:2017-09-22 19:25:40
【问题描述】:

我正在使用支持拖放的 RecyclerView。我的列表项有一排,有两个 TextView、CheckBox、ImageView 用于拖动行。

我正在使用以下链接中的 Helper 类: https://github.com/iPaulPro/Android-ItemTouchHelper-Demo/tree/master/app/src/main/java/co/paulburke/android/itemtouchhelperdemo/helper

当我拖动行时,arrTaxStatus 的值是正确的。

当我启用/禁用复选框时,arrTaxStatus 的值是正确的。

但是当我启用/禁用几个复选框、拖动几行然后再次启用/禁用几个复选框时,我会遇到问题。该位置在 setOnCheckedChangeListener 中受到干扰。即使我点击第一行,我得到一个不同的“位置”

请告诉我如何才能获得单击复选框的正确位置。

代码如下:

public class RecyclerListFragment extends AppCompatActivity implements OnStartDragListener {
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.create_tax_group);

    arrTaxStatus = new ArrayList<Boolean>();
    HashMap<String, Object> temp;
    taxAccounts = new ArrayList<HashMap<String, Object>>();
    Cursor cursor = dh.getDetailsFromTaxGivenTaxCategory();
    if (cursor.moveToFirst()) {
        do {
            temp = new HashMap<String, Object>();
            temp.put("taxName", cursor.getString(cursor.getColumnIndex("scheme_name")));
            temp.put("taxPercent", numberFormat.format(cursor.getDouble(cursor.getColumnIndex("percentage"))));
            taxAccounts.add(temp);
            arrTaxStatus.add(false);
        } while (cursor.moveToNext());
    }
    cursor.close();

    RecyclerListAdapter adapter = new RecyclerListAdapter(this, taxAccounts);

    RecyclerView recyclerView = (RecyclerView) findViewById(android.R.id.list);
    recyclerView.setHasFixedSize(true);
    recyclerView.setAdapter(adapter);
    recyclerView.setLayoutManager(new LinearLayoutManager(this));

    ItemTouchHelper.Callback callback = new SimpleItemTouchHelperCallback(adapter);
    mItemTouchHelper = new ItemTouchHelper(callback);
    mItemTouchHelper.attachToRecyclerView(recyclerView);
}

@Override
public void onStartDrag(RecyclerView.ViewHolder viewHolder) {
    mItemTouchHelper.startDrag(viewHolder);
}

public class RecyclerListAdapter extends RecyclerView.Adapter<RecyclerListAdapter.ItemViewHolder>
        implements ItemTouchHelperAdapter {
    private final OnStartDragListener mDragStartListener;

    public RecyclerListAdapter(OnStartDragListener dragStartListener, ArrayList<HashMap<String, Object>> taxAccounts) {
        mDragStartListener = dragStartListener;
    }

    @Override
    public ItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.create_tax_group_row, parent, false);
        ItemViewHolder itemViewHolder = new ItemViewHolder(view);
        return itemViewHolder;
    }

    @Override
    public void onBindViewHolder(final ItemViewHolder holder, final int position) {
        holder.taxName.setText(taxAccounts.get(position).get("taxName").toString());
        holder.taxPercent.setText(taxAccounts.get(position).get("taxPercent").toString());
        holder.handleView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_DOWN) {
                    mDragStartListener.onStartDrag(holder);
                }
                return false;
            }
        });

        holder.taxStatus.setOnCheckedChangeListener(null);
        holder.taxStatus.setChecked(arrTaxStatus.get(position));
        holder.taxStatus.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                Log.i("arrTaxStatus pos|checked", position + "|" + isChecked);
                arrTaxStatus.set(position, isChecked);
                Log.i("arrTaxStatus onCheckedChanged", arrTaxStatus.toString());
            }
        });
    }

    @Override
    public void onItemDismiss(int position) {
        taxAccounts.remove(position);
        arrTaxStatus.remove(position);
        notifyItemRemoved(position);
    }

    @Override
    public boolean onItemMove(int fromPosition, int toPosition) {
        Collections.swap(taxAccounts, fromPosition, toPosition);
        Collections.swap(arrTaxStatus, fromPosition, toPosition);
        Log.i("arrTaxStatus onItemMove", arrTaxStatus.toString());
        notifyItemMoved(fromPosition, toPosition);
        return true;
    }

    @Override
    public int getItemCount() {
        return taxAccounts.size();
    }

    /**
     * Simple example of a view holder that implements {@link ItemTouchHelperViewHolder} and has a
     * "handle" view that initiates a drag event when touched.
     */
    public class ItemViewHolder extends RecyclerView.ViewHolder implements
            ItemTouchHelperViewHolder {

        public final TextView taxName, taxPercent;
        public final CheckBox taxStatus;
        public final ImageView handleView;

        public ItemViewHolder(View itemView) {
            super(itemView);
            taxName = (TextView) itemView.findViewById(R.id.childname);
            taxPercent = (TextView) itemView.findViewById(R.id.balance);
            taxStatus = (CheckBox) itemView.findViewById(R.id.check_status);
            handleView = (ImageView) itemView.findViewById(R.id.handle);
        }

        @Override
        public void onItemSelected() {
            itemView.setBackgroundColor(Color.LTGRAY);
        }

        @Override
        public void onItemClear() {
            itemView.setBackgroundColor(0);
        }
    }
}
}

【问题讨论】:

    标签: android android-recyclerview android-checkbox


    【解决方案1】:

    您需要在数据模型中创建一个变量,例如 isChecked 或 isEnabled。然后当您启用/禁用它们时。只需更新您用于填充列表的数组。 然后 onBindViewHoder 检查变量值并启用/禁用复选框。

    概念是,一旦您向上/向下移动,行就会被回收。所以复选框不保留值。所以你需要在数组中保留值。然后填充它们。

    【讨论】:

      【解决方案2】:

      不要从 onbindviewholder 获取位置,而是在布局中设置一个包含行位置的标签,而是在更改 onchangelistner 时使用该标签值

      【讨论】:

        【解决方案3】:

        您可以使用来自RecyclerView.Adapter class.notifyItemChanged(int position) 方法来自文档:

        通知任何已注册的观察者该位置的项目已更改。相当于调用notifyItemChanged(position, null);.

        这是一个项目更改事件,而不是结构更改事件。它表明位置数据的任何反映都是过时的,应该更新。位置的项目保持相同的身份。 由于您已经拥有该职位,因此它应该适合您。

        【讨论】:

          【解决方案4】:

          您需要在适配器中维护如下标志:

          private boolean onViewHolderBind;
          
          public ViewHolder(View itemView) {
              super(itemView);
              mCheckBox = (CheckBox) itemView.findViewById(R.id.checkboxId);
              mCheckBox.setOnCheckChangeListener(this);
          }
          
          @Override
          public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
              if(!onViewHolderBind) {
                  // perform your process when checkbox changed
                  notifyDataSetChanged();
              }
          }
          
          ...
          
          @Override
          public void onBindViewHolder(YourAdapter.ViewHolder viewHolder, int position) {
              // process other views 
              // ...
          
              onViewHolderBind = true;
              viewHolder.mCheckBox.setChecked(trueOrFalse);
              onViewHolderBind = false;
          }
          

          【讨论】:

            【解决方案5】:

            我认为您遇到的问题是适配器内部控制的项目与您的数组不同步,问题是 Collections.swap(…) 不执行适配器执行的操作以图形方式 . swap() 将交换数组中两个项目的位置,但范围内的项目保持原位。但是,当用户将项目从最后一个位置拖到第一个位置时,范围内的所有项目位置确实会改变!

            我自己开始使用此代码并通过将 swap() 调用替换为以下代码 (diff) 来修复它:

                  override fun onItemMove(fromPosition: Int, toPosition: Int): Boolean {
             -        Collections.swap(items, fromPosition, toPosition)
             +        val temp = items[fromPosition]
             +        items.removeAt(fromPosition)
             +        items.add(toPosition, temp)
                      notifyItemMoved(fromPosition, toPosition)
                      return true
                  }
            

            为了直观地说明这个错误,我添加了一个dump() 调用,它将在每次拖动交互后显示适配器的内容,然后我创建了一个包含七个元素的适配器,按字母顺序方便地放置:

            Adapter: did load 7
            Adapter: Dumping 7 items
            Adapter: …0 SharingItem(uri=content://FIRST, kind=Image)
            Adapter: …1 SharingItem(uri=content://B, kind=Image)
            Adapter: …2 SharingItem(uri=content://C, kind=Image)
            Adapter: …3 SharingItem(uri=content://D, kind=Audio)
            Adapter: …4 SharingItem(uri=content://E, kind=Audio)
            Adapter: …5 SharingItem(uri=content://F, kind=Video)
            Adapter: …6 SharingItem(uri=content://LAST, kind=Audio)
            

            在 2x4 网格中显示这些项目,我将最后一个项目拖到第一个位置。当我向上拖动手指时,该项目将在拖动过程中发生在集合的不同部分,适配器接收到的每个交互的转储都会突出显示这些部分:

            Adapter: Move from 6 to 4
            Adapter: Dumping 7 items
            Adapter: …0 SharingItem(uri=content://FIRST, kind=Image)
            Adapter: …1 SharingItem(uri=content://B, kind=Image)
            Adapter: …2 SharingItem(uri=content://C, kind=Image)
            Adapter: …3 SharingItem(uri=content://D, kind=Audio)
            Adapter: …4 SharingItem(uri=content://LAST, kind=Audio)
            Adapter: …5 SharingItem(uri=content://F, kind=Video)
            Adapter: …6 SharingItem(uri=content://E, kind=Audio)
            Adapter: Move from 4 to 2
            Adapter: Dumping 7 items
            Adapter: …0 SharingItem(uri=content://FIRST, kind=Image)
            Adapter: …1 SharingItem(uri=content://B, kind=Image)
            Adapter: …2 SharingItem(uri=content://LAST, kind=Audio)
            Adapter: …3 SharingItem(uri=content://D, kind=Audio)
            Adapter: …4 SharingItem(uri=content://C, kind=Image)
            Adapter: …5 SharingItem(uri=content://F, kind=Video)
            Adapter: …6 SharingItem(uri=content://E, kind=Audio)
            Adapter: Move from 2 to 0
            Adapter: Dumping 7 items
            Adapter: …0 SharingItem(uri=content://LAST, kind=Audio)
            Adapter: …1 SharingItem(uri=content://B, kind=Image)
            Adapter: …2 SharingItem(uri=content://FIRST, kind=Image)
            Adapter: …3 SharingItem(uri=content://D, kind=Audio)
            Adapter: …4 SharingItem(uri=content://C, kind=Image)
            Adapter: …5 SharingItem(uri=content://F, kind=Video)
            Adapter: …6 SharingItem(uri=content://E, kind=Audio)
            

            swap() 调用替换为上述实现后,日志显示了交互过程中更好的内部情况:

            Adapter: did load 7
            Adapter: Dumping 7 items
            Adapter: …0 SharingItem(uri=content://FIRST, kind=Image)
            Adapter: …1 SharingItem(uri=content://B, kind=Image)
            Adapter: …2 SharingItem(uri=content://C, kind=Image)
            Adapter: …3 SharingItem(uri=content://D, kind=Audio)
            Adapter: …4 SharingItem(uri=content://E, kind=Audio)
            Adapter: …5 SharingItem(uri=content://F, kind=Video)
            Adapter: …6 SharingItem(uri=content://LAST, kind=Audio)
            Adapter: Move from 6 to 4
            Adapter: Dumping 7 items
            Adapter: …0 SharingItem(uri=content://FIRST, kind=Image)
            Adapter: …1 SharingItem(uri=content://B, kind=Image)
            Adapter: …2 SharingItem(uri=content://C, kind=Image)
            Adapter: …3 SharingItem(uri=content://D, kind=Audio)
            Adapter: …4 SharingItem(uri=content://LAST, kind=Audio)
            Adapter: …5 SharingItem(uri=content://E, kind=Audio)
            Adapter: …6 SharingItem(uri=content://F, kind=Video)
            Adapter: Move from 4 to 2
            Adapter: Dumping 7 items
            Adapter: …0 SharingItem(uri=content://FIRST, kind=Image)
            Adapter: …1 SharingItem(uri=content://B, kind=Image)
            Adapter: …2 SharingItem(uri=content://LAST, kind=Audio)
            Adapter: …3 SharingItem(uri=content://C, kind=Image)
            Adapter: …4 SharingItem(uri=content://D, kind=Audio)
            Adapter: …5 SharingItem(uri=content://E, kind=Audio)
            Adapter: …6 SharingItem(uri=content://F, kind=Video)
            Adapter: Move from 2 to 0
            Adapter: Dumping 7 items
            Adapter: …0 SharingItem(uri=content://LAST, kind=Audio)
            Adapter: …1 SharingItem(uri=content://FIRST, kind=Image)
            Adapter: …2 SharingItem(uri=content://B, kind=Image)
            Adapter: …3 SharingItem(uri=content://C, kind=Image)
            Adapter: …4 SharingItem(uri=content://D, kind=Audio)
            Adapter: …5 SharingItem(uri=content://E, kind=Audio)
            Adapter: …6 SharingItem(uri=content://F, kind=Video)
            

            【讨论】:

              猜你喜欢
              • 2016-09-18
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2014-08-25
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多