我正在使用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;
}

如您所见,我只需在longclick和click(如果actionmode不为空)更改单击项的填充。
一切都按预期工作:如果我长时间单击第一个项目,它的填充确实会改变,但当我滚动到网格底部时,填充已移动到底部图像或其他一些随机图像。再次,如果我滚动到顶部,顶部项将没有填充,并且填充已移动到其他随机元素。
这个问题是由于元素的回收吗?我该怎么处理?

最佳答案

对。这个问题是由于视图的循环使用造成的,是预期的行为。
这很容易理解。滚动回收器视图时,内存中只保留有限的视图集。但正如您所看到的,填充只应用一次,就在单击之后。那么,风景被回收后会发生什么呢?系统将如何记住再次添加填充?
因此,系统通过调用recyclerviewapter的onBindViewHolder()重新绘制视图项,其中的视图保持器可能是其他一些回收项的视图保持器。您需要确保每次调用onBindViewHolder()时都执行两项操作-
1)如果选择了项,则设置填充(这将确保所选项始终得到填充),并且
2)如果未选择项,则将padding设置为0(这将确保随机项不会获得padding。同样,这也是意料之中的,因为选定项的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);
        }
    }
}

10-08 05:43