android - 为什么 RecyclerView 项目在 GridLayoutManager 中随机移动位置?

标签 android android-recyclerview gridlayoutmanager

我正在使用 gridLayoutManager 来显示我的 RecyclerView 项目。我还在项目上实现了 onClick 和 onLongClick

 public void onItemClicked(int position) {
    final SquareImageView clickedItem = (SquareImageView)(lLayout.findViewByPosition(position));

    if (actionMode != null) {
        if(clickedItem.getPaddingLeft() == 1) clickedItem.setPadding(7,7,7,7);
        else clickedItem.setPadding(1,1,1,1);

    } else {
        thumbView = (SquareImageView)(lLayout.findViewByPosition(position));
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.ICE_CREAM_SANDWICH)
            zoomImageFromThumb(position);
        else
        imageFromThumb(position);
    }
}

@Override
public boolean onItemLongClicked(int position) {
    final SquareImageView clickedItem = (SquareImageView)(lLayout.findViewByPosition(position));
    clickedItem.setPadding(7,7,7,7);
    if (actionMode == null) {
        actionMode = startSupportActionMode(new ActionModeCallback());
        actionMode.getMenu().findItem(R.id.menu_remove).setIcon(new IconDrawable(this, Iconify.IconValue.fa_trash).colorRes(R.color.accent_color).actionBarSize());
    }
    return true;
}

如您所见,如果 actionMode 不为空,我只是在 longClick 和点击时更改了被点击项目的填充。

一切都按预期工作:如果我长按第一个项目,它的填充确实会改变,但是当我滚动到网格底部时,填充已经转移到底部图像或其他一些随机图像。同样,如果我滚动到顶部,顶部项目将没有填充,并且填充已转移到其他一些随机元素。

这个问题是由于元素的回收造成的吗?我该如何摆脱它?

最佳答案

是的。此问题是由于 View 的回收造成的,并且是预期的行为。

这个很容易理解。滚动回收器 View 时,只有一组有限的 View 保留在内存中。但如您所见,填充仅应用一次,即在单击之后。那么, View 被回收后会发生什么?系统将如何记住再次添加填充?

因此,系统通过调用 RecyclerViewAdapter 的 onBindViewHolder() 再次重绘 View 项,其中的 View 持有者可能是其他回收项。您需要确保每次调用 onBindViewHolder() 时,您都会做两件事 -

1) 如果项目被选中则设置填充(这确保您选择的项目总是得到填充),以及

2) 如果未选择项目,则将填充设置为 0(这可确保随机项目不会获得填充。同样,这是预期的,因为所选项目的 ViewHolder可以重复用于未选择的项目!))

您可以使用 SparseBooleanArray 来存储所选位置并在 onBindViewHolder 中检查其值。请记住,您还需要使用单击后的位置调用 notifyItemChanged(i),以便重新绘制该项目(再次调用 onBindViewHolder())。

大致上,您可以在适配器的代码中添加两件事:

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder>{
    //...
    private SparseBooleanArray selectedItems = new SparseBooleanArray();

    // Call this from your onItemLongClicked()
    public void selectItem(int position){
        selectedItems.put(position, true);
        notifyItemChanged(position);
    }

    // Call this in your onItemClicked() to check if position is selected
    public boolean isItemSelected(int position){
        return selectedItems.get(position, false);
    }

    @Override
    public void onBindViewHolder(final ViewHolder holder, final int position) {
        // your existing code
        if(selectedItems.get(position, false)){
        holder.itemView.setPadding(7,7,7,7);
        }
        else {
            holder.itemView.setPadding(1,1,1,1);
        }
    }
}

关于android - 为什么 RecyclerView 项目在 GridLayoutManager 中随机移动位置?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31529782/

相关文章:

android - 嵌套 ScrollView 中的两个 Recyclerview

android - RecyclerView with GridLayoutManager in RecyclerView with LinearLayoutManager

使用 GridLayoutManager 时 Android RecyclerView 单元格始终保持对齐

xml - Ellipsize 不适用于自定义 listView 中的 textView

android - 如何在 StaggeredGridLayoutManager 中实现动态行跨度

android - 如何从SD卡加载android中的xml布局文件

java - 以编程方式添加多种 View 类型的 RecyclerView

java - 如何制作一个正方形来查看画廊?

Android:带有自定义标题的圆角 TextView XML 布局

android - 你如何在 Android cmake 外部构建系统中链接第三方库?