RecyclerView Android中setOnCheckedChangeListener位置值面临的问题 [英] Facing issue in setOnCheckedChangeListener position value in RecyclerView Android

查看:85
本文介绍了RecyclerView Android中setOnCheckedChangeListener位置值面临的问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用支持拖放的RecyclerView.我的列表项中有一行,其中有两个TextView,CheckBox和ImageView用于拖动行.

I am using RecyclerView which supports dragging and dropping. My list item has a row with two TextView, CheckBox, ImageView for dragging rows.

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

I am using Helper classes from below link: https://github.com/iPaulPro/Android-ItemTouchHelper-Demo/tree/master/app/src/main/java/co/paulburke/android/itemtouchhelperdemo/helper

拖动行时arrTaxStatus的值正确.

Values of arrTaxStatus are correct when I drag the rows.

启用/禁用复选框后,arrTaxStatus的值正确.

Values of arrTaxStatus are correct when I enable/disable the checkboxes.

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

But I face issues when I enable/disable few checkboxes, drag few rows and then again enable/disable few checkboxes. The position gets disturbed in setOnCheckedChangeListener. Even though I am clicking on first row, I get a different 'position'

请告诉我如何获得所单击复选框的正确位置.

Please tell me how can I get the correct position of the clicked checkbox.

以下代码:

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);
        }
    }
}
}

推荐答案

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

I think the problem you are suffering is that the items controlled internally by the adapter are not in sync with your arrays, the problem being that Collections.swap(…) doesn't do what the adapters perform graphically. A swap() will exchange the position of two items in an array, but the items inside the range remain in position. However, when a user drags an item from the last position to the first position, all the item positions inside the range do change!

我自己开始使用此代码,并通过使用以下代码(diff)替换swap()调用来修复了该问题:

I started using this code myself and fixed it by replacing the swap() call with the following code (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()调用,该调用将在每次拖动交互后显示适配器的内容,然后创建了一个具有七个元素的适配器,方便地按字母顺序放置:

To illustrate visually the bug, I added a dump() call which would show the contents of the Adapter after each drag interaction, then I created an adapter with seven elements, conveniently placed in alphabetical order:

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网格中,将最后一个项目拖到第一个位置.当我向上拖动手指时,该项将在拖动过程中在集合的不同部分中发生( ),突出显示为适配器接收到的每个 interaction 的转储:

Displaying these items in a 2x4 grid, I dragged the last item to the first position. As I dragged the finger up, the item would take place in different parts of the collection during the drag movement, which are highlighted by the dumps for each interaction received by the adapter:

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()调用后,日志显示了交互过程中内部的更好图片:

After replacing the swap() call with the implementation above, the logs showed a much better picture of the internals during interaction:

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)

这篇关于RecyclerView Android中setOnCheckedChangeListener位置值面临的问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆