【问题标题】:Android RecyclerView: why is first item in list already selected?Android RecyclerView:为什么列表中的第一项已被选中?
【发布时间】:2016-08-07 20:59:29
【问题描述】:

我有一个默认背景为白色的 CardView 的 RecyclerView 列表。我设置了一个 OnLongClickListener 来选择 CardView 并加载一个 DialogFragment 以确认删除项目(CardView)并将背景颜色更改为红色。

一切正常,除了列表中创建的第一个 CardView 已经显示红色背景,即使用户没有 OnLongClicked CardView。此后,添加的最新 CardView 始终显示红色背景,即使用户尚未 OnLongClicked CardView。我在这里错过了什么?

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">
    ...

适配器文件:

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

【问题讨论】:

    标签: android android-recyclerview android-adapter


    【解决方案1】:

    您需要声明一个外部数组来跟踪所选项目。让我们有一个与列表大小相同的数组。

    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;
    

    现在在您的适配器中,当单击一个项目时,将 1 设置在 selectedArray 的适当位置。这样,我们就可以跟踪现在选择了哪个项目。

    现在修改你的适配器代码如下

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

    在你的onBindViewHolder

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

    您的updateSelectedArray() 可能如下所示

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

    从列表中删除项目后,您需要重置 selectedArray`,因为该项目在您的列表中不再可用。

    所以你的deleteFromList 函数可能看起来像:

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

    我采用了一个数组来跟踪所选项目。但是您可以使用ArrayList 或任何您喜欢的数据结构来跟踪它。这个想法是正确跟踪所选项目。

    更新

    列表中随机选择项目的问题是由于未正确绑定视图造成的。所以当你删除一个项目时,你需要做以下事情。

    • 重置您在 selectedArray 中的选定位置。即selectedPos = -1
    • 从列表中删除该项目。
    • 致电notifyDatasetChanged 以使您的更改生效 列表。

    最重要的是不要忘记设置else 部分。我的意思是

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

    【讨论】:

    • 对不起,我一定没有说清楚。对于 onLongClick(),我只允许用户在 RecyclerView 列表中长按一个 CardView。该方法用于更改所选 CardView 的 BackgroundColor,然后加载确认用户要删除 CardView 的 DialogFragment。
    • 是的,这也适用于您的情况。你现在面临的问题是什么?这是我其他答案中toggleSelection 的简化版本。您不必在这里实现toggleSelection
    • 我能够通过更改“private int selectedPos;”来修复第一个 CardView 错误地突出显示的问题;到“私人int selectedPos = -1;”我还有一个问题。删除突出显示的 CardView 后,刷新 RecyclerList 并且其他 CardViews 随机将其背景颜色切换为红色,即使没有任何 CardViews 已被 LongClicked。就好像已删除 CardView 的旧位置仍保留在 RecyclerView 列表中,因此占据该位置的另一个 Cardview 错误地更改了其 BackgroundColor。有什么想法吗?
    • 好的,我试试。 “else”部分应该是 ...setSelected(false) 吗?
    • 是的。请试一试,让我知道这是否有效。如果您再次遇到任何困难,请随时询问。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-07-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多