问题
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