Android RecyclerView: why is first item in list already selected?

痴心易碎 提交于 2019-12-11 04:28:13

问题


I have a RecyclerView list of CardViews with a defaultbackground of white. I set up a OnLongClickListener to select the CardView and load a DialogFragment to confirm deletion for the item (CardView) and change the background color to red.

Everything is working correctly except the first CardView created in the list is already showing a red background even though the user has not OnLongClicked the CardView. Thereafter, the newest CardView added always shows the red background even when the user has not yet OnLongClicked the CardView. What am I missing here?

background_selector.xml:

...
<!-- Normal state. -->
<item android:drawable="@color/list_contact_item_default"
    android:state_pressed="false"
    android:state_selected="false"  />

<!-- Selected state. -->

<item android:drawable="@color/item_selected"
    android:state_pressed="false"
    android:state_selected="true" />

</selector>

list_contact_tem.xml:

<android.support.v7.widget.CardView
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/singlecard_view1"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="10dp"
    card_view:cardCornerRadius="6dp"
    card_view:cardElevation="4dp"  >

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@drawable/background_selector">
    ...

Adapter file:

public class ContactListAdapter extends RecyclerView.Adapter<ContactListAdapter.ContactHolder>{
    ...
    private int selectedPos;

    @Override
    public ContactHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_contact_item, parent, false);

    final ContactHolder contactHolder = new ContactHolder(view);

    // Attach a LongClick listener to the items's (row) view.
    contactHolder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
        @Override
        public boolean onLongClick(View view) {
            // Save the new selected position.
            selectedPos = contactHolder.getAdapterPosition(); // get the item position.
            if (selectedPos != RecyclerView.NO_POSITION) {
                if (recyclerItemClickListener != null) {
                    recyclerItemClickListener.onItemLongClick(selectedPos, contactHolder.itemView);
                        // Temporarily save the last selected position
                        int lastSelectedPosition = selectedPos;
                        // Update the previous selected row
                        notifyItemChanged(lastSelectedPosition);
                        notifyItemChanged(selectedPos);
                }
            }
            return true;
        }
    });

    return contactHolder;
    }

    @Override
    public void onBindViewHolder(ContactHolder holder, int position) {
        final Contact contact = contactList.get(position);

        if(position == selectedPos) {
            holder.itemView.setSelected(true);
        } else {
            holder.itemView.setSelected(false);
        }

    holder.thumb.setImageBitmap(letterBitmap);
    holder.name.setText(contact.getName());
    holder.phone.setText(contact.getPhone());
}             

回答1:


You need to declare an external array to keep track of the items selected. Let us have an array which have the same size as the list.

private int[] selectedArray = new int[yourList.size()];

// Now initialize the Array with all zeros
for(int i=0; i<selectedArray.length; i++)
    selectedArray[i] = 0;

Now inside your adapter, when an item is clicked, set 1 in the proper position in the selectedArray. So that, we can keep track which item is selected now.

Now modify your adapter code as follows

// Attach a LongClick listener to the items's (row) view.
contactHolder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
    @Override
    public boolean onLongClick(View view) {
        // Update the selectedArray. Set 1 for the selected item
        // and 0 for the others.
        updateSelectedArray(contactHolder.getAdapterPosition());

        if (selectedPos != RecyclerView.NO_POSITION) {
            if (recyclerItemClickListener != null) {
                recyclerItemClickListener.onItemLongClick(selectedPos, contactHolder.itemView);

                // Repopulate the list here
                notifyDatasetChanged();
            }
        }
        return true;
    }
});

And in your onBindViewHolder

final int SELECTED = 1;
if(selectedArray[position] == SELECTED) {
    holder.itemView.setSelected(true);
} else {
    holder.itemView.setSelected(false);
}

Your updateSelectedArray() may look like this

private void updateSelectedArray(int position) {
    for(int i=0; i<selectedArray.length; i++){
        if(i == position) selectedArray[i] = 1;
        else selectedArray[i] = 0;
    }
}

And after you delete an item from the list, you need to reset the selectedArray` as the item is no longer available in your list.

So your deleteFromList function may look like:

private void deleteFromList(int position)
{
    yourList.remove(position);
    selectedArray = new int[yourList.size()];

    // Now re-initialize the Array with all zeros
    for(int i=0; i<selectedArray.length; i++)
        selectedArray[i] = 0;
}

I've taken an array to keep track of the selected item. But you can take an ArrayList or any data structure you like to keep track of it. The idea is to keep track of the selected item properly.

Update

The problem of having randomly selected items in your list is caused by not binding your views properly. So when you delete an item, you need to do the following things.

  • Reset your selected position in the selectedArray. i.e. selectedPos = -1
  • Remove the item from the list.
  • Call notifyDatasetChanged to take the effect of your changes in the list.

And most importantly don't forget to set the else part. What I meant is

// Pseudo code
if(position == selected) itemView.setSelected(true);
else itemView.setSelected(true); // Don't forget this else 


来源:https://stackoverflow.com/questions/38818499/android-recyclerview-why-is-first-item-in-list-already-selected

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!