在Android RecyclerView中实现多选

时间:2017-06-23 07:05:25

标签: android android-recyclerview android-adapter gridlayoutmanager

我需要一些Multi / Single选择的帮助。找到了我想要的here,因为它简单。 我正在使用GridLayoutManager我的适配器中包含超过90个项目,CardView包含TextViewImageView,同时使用{{3}中所述的过程}。

当我选择一个或多个项目时,当我向下滚动时,其他项目“似乎”被选中,因为背景复制,但它们未被选中。 尝试将setOnClickListener放在onBindViewHolder中,也放在MyViewHolder类中,在两者中我都得到了相同的行为。向下滚动时,似乎选择了其他项目。 在适配器中使用了notifyItemChanged(position)notifyDataSetChanged(),但后台根本没有变化,尽管setSelected正常工作。 我还在RecyclerView设置中使用了setHasFixedSize(true)

onBindViewHolder

@Override
public void onBindViewHolder(MyViewHolder myViewHolder, final int position) {

    PatternImages currentPattern = patternImages.get(position);
    myViewHolder.setData(currentPattern, position);
    myViewHolder.itemView.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {

            v.setSelected(!v.isSelected());
            if (v.isSelected()) {
                v.setBackgroundColor(ContextCompat.getColor(context, R.color.colorPrimaryHighLight));

            } else {
                v.setBackgroundColor(Color.WHITE);

            }
            notifyItemChanged(position);
        }
    });
}

模型

public class PatternImages {

    private int imageId, imageName;
    private boolean isSelected;

    public PatternImages(int imageId, int imageName, boolean isSelected) {

        this.imageId = imageId;
        this.imageName = imageName;
        this.isSelected = isSelected;
    }
    public int getImageId() {

        return imageId;
    }
    public void setImageId(int imageId) {

        this.imageId = imageId;
    }
    public int getImageName() {

        return imageName;
    }
    public void setImageName(int imageName) {

        this.imageName = imageName;
    }
    public boolean isSelected() {

        return isSelected;
    }
    public void setSelected(boolean selected) {

        isSelected = selected;
    }

RecyclerView设置

 private void setUpPatternsRecyclerView() {

    RecyclerView recyclerPatternsView = (RecyclerView) findViewById(R.id.pattern_image_recycler_view);
    PatternImageAdapter adapter = new PatternImageAdapter(this, patternImages);
    recyclerPatternsView.setAdapter(adapter);
    ColumnQty columnQty = new ColumnQty(this, R.layout.item_image_pattern_cardview);
    GridLayoutManager gridLayoutManager = new GridLayoutManager(getApplicationContext(), columnQty.calculateNoOfColumns());
    recyclerPatternsView.setHasFixedSize(true);
    recyclerPatternsView.setLayoutManager(gridLayoutManager);
    recyclerPatternsView.setItemAnimator(new DefaultItemAnimator());
    recyclerPatternsView.addItemDecoration(new GridSpacing(columnQty.calculateSpacing()));

}

setData方法

public void setData(PatternImages currentPattern, int position) {

    this.position = position;
    patternName.setText(context.getString(currentPattern.getImageName()));
    patternName.setTypeface(Typeface.createFromAsset(context.getAssets(), "fonts/ElMessiri-SemiBold.ttf"));
    patternImage.setBackgroundResource(currentPattern.getImageId());
    if (position == 0 || position == 1) {
        animationDrawable = (AnimationDrawable) patternImage.getBackground();
        animationDrawable.start();
    }


}

4 个答案:

答案 0 :(得分:4)

RecyclerView顾名思义,回收视图。这意味着一旦视图滚出屏幕,就可以重复使用。

在重复使用视图之前,它仍包含上次使用时的所有设置。例如,如果它包含TextView,则TextView仍将其Text属性设置为上次显示的内容。

某些项目"似乎"选择是因为您选择的已离开屏幕的视图现在正在重复使用,而您尚未取消选择它们。

OnBindViewHolder方法中,您需要"重置"所有视图都恢复为默认值。在这种情况下,将关闭"关闭"用于制作视图的任何方法都会被选中。

例如:

@Override
public void onBindViewHolder(MyViewHolder myViewHolder, final int position) {

    final PatternImages currentPattern = patternImages.get(position);

    myViewHolder.setData(currentPattern, position);
    myViewHolder.itemView.setBackgroundColor(currentPattern.isSelected() ?R.color.Red: R.color.WHITE); // choose your colors

    myViewHolder.itemView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            currentPattern.setSelected(!currentPattern.isSelected())
            notifyItemChanged(position);
        }
    });
}

基本上,每次绑定时,都会根据模型中的相关属性将背景颜色设置为选定状态或非选定状态。

答案 1 :(得分:2)

最近,我参与了recyclerview多选,所以你可以先尝试初始化sparseboolean,boolean这样一个int:

private SparseBooleanArray storeChecked = new SparseBooleanArray();
private boolean isMultiselect;
private int itemSelected;

所以在bindViewHolder上添加这个

holder.view.setbackground(storechecked.get(position) ? Color.White : Color.Black)

然后, 实现onLongClickListener。 在longClick上 加上这个:

if(!ismultiSelect){
  storechecked.put(getAdapterPosition(), true);
  notifyDataSetChanged(getAdapterPosition());
  triggerOnLongClickListener(++itemSelected); // using listerner i've transfer position to fragment for actionmode selected count

}


在此之后,在onClick上执行此操作:

if(ismultiSelect){
   boolean tof = storechecked.get(getAdapterPosition());
           if (tof){
                triggerOnItemClickListener(--itemSelected, v); // transfer position to update unselected 
                storeChecked.delete(position);// delete position of unselected position in the fragment
            }else {
                triggerOnItemClickListener(++itemSelected, v);
             // transfer position to update selected  position in the fragment
        }
    } 

 **Other methods in adapter**

   //clear on actionmode close
   public void exitMultiselectMode() {
    isMultiselect = false;
    itemSelected = 0;
    storeChecked.clear();
    notifyDataSetChanged();
 }

   // get all selected position
   public List<Integer> getSelectedItems() {
     List<Integer> items = new ArrayList<>(storeChecked.size());
     for (int i = 0; i < storeChecked.size(); ++i) {
         items.add(storeChecked.keyAt(i));
     }
     return items;
  }

答案 2 :(得分:1)

尝试将状态保留在模型中但在视图中,并将模型绑定到onBindViewHolder中的视图。

答案 3 :(得分:0)

我尝试了@Kuffs解决方案,并且我发布了我的最终代码以供参考。

onBindViewHolder

@Override
public void onBindViewHolder(final MyViewHolder myViewHolder, final int position) {

    final PatternImages currentPattern = patternImages.get(position);
    myViewHolder.setData(currentPattern, position);
    myViewHolder.itemView.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            currentPattern.setSelected(!currentPattern.isSelected());

            notifyItemChanged(position);
        }
    });

}

setData()方法

public void setData(PatternImages currentPattern, int position) {

    this.position = position;
    patternName.setText(context.getString(currentPattern.getImageName()));
    patternName.setTypeface(Typeface.createFromAsset(context.getAssets(), "fonts/ElMessiri-SemiBold.ttf"));
    patternImage.setBackgroundResource(currentPattern.getImageId());
    if (position == 0 || position == 1) {
        animationDrawable = (AnimationDrawable) patternImage.getBackground();
        animationDrawable.start();
    }
    itemView.setBackgroundColor(currentPattern.isSelected() ? ContextCompat.getColor(context, R.color.colorPrimaryHighLight) : Color.WHITE);
}