在 Android RecyclerView 中实现多选
Implementing multi selection in Android RecyclerView
我需要一些关于 Multi/Single selection 的帮助。找到了我要找的东西 ,因为它很简单。
我正在使用 GridLayoutManager
我的适配器中有 90 多个项目,一个 CardView
和一个 TextView
和一个 ImageView
,同时使用 [=27= 中描述的过程].
当我 select 一个或多个项目时,当我向下滚动时,其他项目 "seems" 被 select 编辑,因为背景复制了,但它们不是 select编辑。
尝试将 setOnClickListener
放置在 onBindViewHolder
以及 MyViewHolder class 中,并且在它们中我得到相同的行为。向下滚动时,其他项目似乎被 selected。
在适配器中使用 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();
}
}
A RecyclerView
顾名思义,回收视图。这意味着一旦视图滚出屏幕,就可以重新使用它。
在重新使用视图之前,它仍然包含上次使用时的所有设置。例如,如果它包含 TextView
,则 TextView
的文本 属性 仍将设置为上次显示时的文本。
某些项目 "seem" 被选中的原因是您选择的滚动到屏幕外的视图现在被重新使用,而您没有取消选择它们。
在您的 OnBindViewHolder
方法中,您需要 "reset" 将所有视图恢复为默认值。在这种情况下,"turn off" 无论您使用何种方法使视图显示为已选中。
例如:
@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);
}
});
}
本质上,每次绑定时,根据模型中的相关属性将背景颜色设置为选中或未选中状态。
最近,我在研究 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。
长按
添加:
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;
}
尽量在模型中保持状态在视图中,并将模型绑定到视图中onBindViewHolder
。
我尝试了@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);
}
我需要一些关于 Multi/Single selection 的帮助。找到了我要找的东西 GridLayoutManager
我的适配器中有 90 多个项目,一个 CardView
和一个 TextView
和一个 ImageView
,同时使用 [=27= 中描述的过程].
当我 select 一个或多个项目时,当我向下滚动时,其他项目 "seems" 被 select 编辑,因为背景复制了,但它们不是 select编辑。
尝试将 setOnClickListener
放置在 onBindViewHolder
以及 MyViewHolder class 中,并且在它们中我得到相同的行为。向下滚动时,其他项目似乎被 selected。
在适配器中使用 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();
}
}
A RecyclerView
顾名思义,回收视图。这意味着一旦视图滚出屏幕,就可以重新使用它。
在重新使用视图之前,它仍然包含上次使用时的所有设置。例如,如果它包含 TextView
,则 TextView
的文本 属性 仍将设置为上次显示时的文本。
某些项目 "seem" 被选中的原因是您选择的滚动到屏幕外的视图现在被重新使用,而您没有取消选择它们。
在您的 OnBindViewHolder
方法中,您需要 "reset" 将所有视图恢复为默认值。在这种情况下,"turn off" 无论您使用何种方法使视图显示为已选中。
例如:
@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);
}
});
}
本质上,每次绑定时,根据模型中的相关属性将背景颜色设置为选中或未选中状态。
最近,我在研究 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。
长按
添加:
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;
}
尽量在模型中保持状态在视图中,并将模型绑定到视图中onBindViewHolder
。
我尝试了@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);
}