如何 select 回收站视图中的多个项目 android?
How to select multiple items in recycler view android?
我想在回收站视图中 select 多个项目,当它被 selected 时,我想将可见性设置为该项目的复选框可见。所以,很长一段时间我都可以使用接口设置 onlongClickListner
并在片段中处理 onLongClick
事件。
只要用户长按任何项目,应用程序的 onCLick
逻辑就会改变。长按应用程序在另一个 activity 中打开项目,但是,长按后 onClick
的逻辑发生了变化,可以根据需要进行设置。我想在长按后选中与该项目对应的复选框。并想从回收站视图中加载的 arrayList
添加它。
片段
...
@Override
public void onclick(int position) {
if (!isSelectionMode) {
Intent intent = new Intent(getActivity(), FullPhoto.class);
intent.putExtra("uri", arrayList.get(position).getUri());
startActivity(intent);
}
}
//Support fun to turn selectionMode on, onLongClick event.
@Override
public void onLongClick() {
isSelectionMode = true;
}
...
适配器
...
public static class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener,View.OnLongClickListener {
private final ImageView img;
public CheckBox selection;
OnImageClickListner listner;
OnImageLongClickListener longClickListener;
public MyViewHolder(@NonNull View itemView, OnImageClickListner listner,OnImageLongClickListener longClickListener) {
super(itemView);
this.listner = listner;
this.longClickListener = longClickListener;
itemView.setOnLongClickListener(this); //onLongClickListener is set to all of the RecyclerView Items for once rather than setting on each item in BindViewHolder for repeated times
itemView.setOnClickListener(this); //onClickListener is set to all of the RecyclerView Items for once rather than setting on each item in BindViewHolder for repeated times
img = itemView.findViewById(R.id.img);
selection = itemView.findViewById(R.id.checkbox);
}
@Override
public void onClick(View v) {
listner.onclick(getAdapterPosition()); //Returning the current clicked position
}
@Override
public boolean onLongClick(View v) {
longClickListener.onLongClick();
return true;
}
}
// inner class ends
public interface OnImageClickListner{ //Interface to generate call back when user clicked an image.
void onclick(int position);
}
public interface OnImageLongClickListener{ //Interface to generate call back when user long clicked an image.
void onLongClick();
}
...
在这种情况下,我无法理解如何实施 selection 跟踪器。我可以使用 getAdapterPosition()
获取适配器位置,然后我可以从该索引上的 arrayList
中删除元素。但是,我想突出显示 position
处的复选框。在这种情况下,我无法实现代码。
我试过的东西
我确实尝试从 onLongClick(View v)
传递 View v
,然后将 selection
复选框传递给 onCLick()
事件。但是,它没有用。
我想 select 回收站视图中的项目并将 selected 项目的可见性设置为 VISIBLE
。
------ 更新 ------
借助事件方法中的少量编辑,我现在可以将复选框的可见性设置为可见。
片段
@Override
public void onclick(int position, CheckBox selection) {
if (!isSelectionMode) {
Intent intent = new Intent(getActivity(), FullPhoto.class);
intent.putExtra("uri", arrayList.get(position).getUri());
startActivity(intent);
}
else
{
selection.setVisibility(View.VISIBLE);
selection.setChecked(true);
}
}
其中 selection
是适配器从 MyViewHolder
class 传递的复选框。但是,由于回收者观点的性质,我得到了双 select 离子。还有一个奇怪的问题,如果我向下滚动 selecting 项目后,selections 将随机更改。
如您所见,在这张图片中,我只 select 编辑了 4 张图像,但是当我向下滚动时,其他图像也被 select 编辑了,当我再次向上滚动时,它弄乱了我的select 编辑了项目。
照片适配器
public class PhotosAdapter extends RecyclerView.Adapter<PhotosAdapter.MyViewHolder> {
public Context context;
ArrayList<ImageModel> arrayList;
Activity activity;
OnImageClickListner listener;
OnImageLongClickListener longClickListener;
/*=============================================================== CONSTRUCTOR ===============================================================*/
public PhotosAdapter(Context context, ArrayList<ImageModel> arrayList, Activity activity, OnImageClickListner listner, OnImageLongClickListener longClickListener) {
this.context = context;
this.arrayList = arrayList;
this.activity = activity;
this.listener = listner;
this.longClickListener = longClickListener;
}
/*=============================================================== OVERRIDDEN METHODS ===============================================================*/
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { //This methods returns single_view.xml as a view for RecyclerView.
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.single_view, parent, false);
return new MyViewHolder(view, listener, longClickListener);
}
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position) { //Binding the uris with each view depending upon the position of current view.
activity.runOnUiThread(() -> GlideApp.with(context)
.load(Uri.parse(arrayList.get(position).getUri()))
.apply(RequestOptions.overrideOf(150, 150)) //It overrides the value of original image and reduces it to the visible thumbnail size.
.diskCacheStrategy(DiskCacheStrategy.RESOURCE) //Then it caches the reduced size thumbnail for faster loading speed.
.into(holder.img));
}
@Override
public int getItemCount() {
return arrayList.size();
}
/*=============================================================== INNER VIEW HOLDER CLASS ===============================================================*/
public static class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener {
private final ImageView img;
public CheckBox selection;
OnImageClickListner listener;
OnImageLongClickListener longClickListener;
public final SparseBooleanArray selectedItems; ///////////////////////////////// ADDED LINE /////////////////////////////////
public MyViewHolder(@NonNull View itemView, OnImageClickListner listener, OnImageLongClickListener longClickListener) {
super(itemView);
this.listener = listener;
this.longClickListener = longClickListener;
itemView.setOnLongClickListener(this); //onLongClickListener is set to all of the RecyclerView Items for once rather than setting on each item in BindViewHolder for repeated times
itemView.setOnClickListener(this); //onClickListener is set to all of the RecyclerView Items for once rather than setting on each item in BindViewHolder for repeated times
img = itemView.findViewById(R.id.img);
selection = itemView.findViewById(R.id.checkbox);
selectedItems = new SparseBooleanArray(); ///////////////////////////////// ADDED LINE /////////////////////////////////
}
@Override
public void onClick(View v) {
listener.onclick(getAdapterPosition(), selection); //Returning the current clicked position and selection checkbox to the implemented method.
}
@Override
public boolean onLongClick(View v) {
longClickListener.onLongClick(getAdapterPosition(), v); //Returning the current clicked position and view to the implemented method.
return true;
}
//////////////////////////////////////////////////////////////////////////// ADDED LINES ////////////////////////////////////////////////////////////////////////////
boolean isSelected(int position) {
return getSelectedItems().contains(position);
}
public void toggleSelection(int position) {
if (selectedItems.get(position, false)) {
selectedItems.delete(position);
} else {
selectedItems.put(position, true);
}
notifyItemChanged(position);
}
public void selectAll() {
for (int i = 0; i < getItemCount(); i++) {
if (!(selectedItems.get(i, false))) {
selectedItems.put(i, true);
}
notifyItemChanged(i);
}
notifyDataSetChanged();
}
public void clearSelection() {
List<Integer> selection = getSelectedItems();
selectedItems.clear();
for (Integer i : selection) {
notifyItemChanged(i);
}
}
public int getSelectedItemCount() {
return selectedItems.size();
}
public List<Integer> getSelectedItems() {
List<Integer> items = new ArrayList<>(selectedItems.size());
for (int i = 0; i < selectedItems.size(); ++i) {
items.add(selectedItems.keyAt(i));
}
return items;
}
} //INNER CLASS ENDS
/*=============================================================== INTERFACES ===============================================================*/
public interface OnImageClickListner { //Interface to generate call back when user clicked an image.
void onclick(int position, CheckBox selection);
}
public interface OnImageLongClickListener { //Interface to generate call back when user long clicked an image.
void onLongClick(int position, View v);
}
}
这就是导致双重或多重选择的原因。
Recyclerview 以这种方式工作,视图被回收。
因此您必须在每次展开视图时隐藏、选中或取消选中每个项目。
所以在 onbindViewholder
中,你必须 setChecked()
为 true 或 false,具体取决于你的情况。
我解决这个问题的方法是:
不要将视图传递给父片段,而是以这种方式在适配器中保留检查逻辑:
if (isItemSelected){
selection.setChecked(true);
}else{
selection.setChecked(false);
}
这样就可以完美的勾选和取消勾选了。
--更新--
创建Selectable适配器class提供isSelected()
方法如下
可选适配器
public abstract class SelectableAdapter<VH extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<VH> {
private static final String TAG = SelectableAdapter.class.getSimpleName();
private final SparseBooleanArray selectedItems;
SelectableAdapter() {
selectedItems = new SparseBooleanArray();
}
boolean isSelected(int position) {
return getSelectedItems().contains(position);
}
public void toggleSelection(int position) {
if (selectedItems.get(position, false)) {
selectedItems.delete(position);
} else {
selectedItems.put(position, true);
}
notifyItemChanged(position);
}
public void selectAll() {
for (int i = 0; i < getItemCount(); i++) {
if (!(selectedItems.get(i, false))) {
selectedItems.put(i, true);
}
notifyItemChanged(i);
}
notifyDataSetChanged();
}
public void clearSelection() {
List<Integer> selection = getSelectedItems();
selectedItems.clear();
for (Integer i : selection) {
notifyItemChanged(i);
}
}
public int getSelectedItemCount() {
return selectedItems.size();
}
public List<Integer> getSelectedItems() {
List<Integer> items = new ArrayList<>(selectedItems.size());
for (int i = 0; i < selectedItems.size(); ++i) {
items.add(selectedItems.keyAt(i));
}
return items;
}
}
让您的适配器扩展 selectableAdapter
如下:
适配器Class
public class RecyclerViewAdapter extends SelectableAdapter<RclAdapter.ViewHolder>
在片段上使用 toggleSelection
将位置设置为选中或未选中。
@Override
public void onclick(int position) {
if (!isSelectionMode) {
Intent intent = new Intent(getActivity(), FullPhoto.class);
intent.putExtra("uri", arrayList.get(position).getUri());
startActivity(intent);
}
else
{
// Use the adapter instance here
adapter.toggleSelection(position);
}
}
记住 toggleSelection
通知适配器并调用 onBindViewHolder
。
在适配器中:onBindViewHolder
实现选择逻辑以显示和隐藏复选框。
如果只设置为View.VISIBLE
,未选中的不设置为View.GONE
,还是一样的问题。
我想在回收站视图中 select 多个项目,当它被 selected 时,我想将可见性设置为该项目的复选框可见。所以,很长一段时间我都可以使用接口设置 onlongClickListner
并在片段中处理 onLongClick
事件。
只要用户长按任何项目,应用程序的 onCLick
逻辑就会改变。长按应用程序在另一个 activity 中打开项目,但是,长按后 onClick
的逻辑发生了变化,可以根据需要进行设置。我想在长按后选中与该项目对应的复选框。并想从回收站视图中加载的 arrayList
添加它。
片段
...
@Override
public void onclick(int position) {
if (!isSelectionMode) {
Intent intent = new Intent(getActivity(), FullPhoto.class);
intent.putExtra("uri", arrayList.get(position).getUri());
startActivity(intent);
}
}
//Support fun to turn selectionMode on, onLongClick event.
@Override
public void onLongClick() {
isSelectionMode = true;
}
...
适配器
...
public static class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener,View.OnLongClickListener {
private final ImageView img;
public CheckBox selection;
OnImageClickListner listner;
OnImageLongClickListener longClickListener;
public MyViewHolder(@NonNull View itemView, OnImageClickListner listner,OnImageLongClickListener longClickListener) {
super(itemView);
this.listner = listner;
this.longClickListener = longClickListener;
itemView.setOnLongClickListener(this); //onLongClickListener is set to all of the RecyclerView Items for once rather than setting on each item in BindViewHolder for repeated times
itemView.setOnClickListener(this); //onClickListener is set to all of the RecyclerView Items for once rather than setting on each item in BindViewHolder for repeated times
img = itemView.findViewById(R.id.img);
selection = itemView.findViewById(R.id.checkbox);
}
@Override
public void onClick(View v) {
listner.onclick(getAdapterPosition()); //Returning the current clicked position
}
@Override
public boolean onLongClick(View v) {
longClickListener.onLongClick();
return true;
}
}
// inner class ends
public interface OnImageClickListner{ //Interface to generate call back when user clicked an image.
void onclick(int position);
}
public interface OnImageLongClickListener{ //Interface to generate call back when user long clicked an image.
void onLongClick();
}
...
在这种情况下,我无法理解如何实施 selection 跟踪器。我可以使用 getAdapterPosition()
获取适配器位置,然后我可以从该索引上的 arrayList
中删除元素。但是,我想突出显示 position
处的复选框。在这种情况下,我无法实现代码。
我试过的东西
我确实尝试从 onLongClick(View v)
传递 View v
,然后将 selection
复选框传递给 onCLick()
事件。但是,它没有用。
我想 select 回收站视图中的项目并将 selected 项目的可见性设置为 VISIBLE
。
------ 更新 ------
借助事件方法中的少量编辑,我现在可以将复选框的可见性设置为可见。
片段
@Override
public void onclick(int position, CheckBox selection) {
if (!isSelectionMode) {
Intent intent = new Intent(getActivity(), FullPhoto.class);
intent.putExtra("uri", arrayList.get(position).getUri());
startActivity(intent);
}
else
{
selection.setVisibility(View.VISIBLE);
selection.setChecked(true);
}
}
其中 selection
是适配器从 MyViewHolder
class 传递的复选框。但是,由于回收者观点的性质,我得到了双 select 离子。还有一个奇怪的问题,如果我向下滚动 selecting 项目后,selections 将随机更改。
如您所见,在这张图片中,我只 select 编辑了 4 张图像,但是当我向下滚动时,其他图像也被 select 编辑了,当我再次向上滚动时,它弄乱了我的select 编辑了项目。
照片适配器
public class PhotosAdapter extends RecyclerView.Adapter<PhotosAdapter.MyViewHolder> {
public Context context;
ArrayList<ImageModel> arrayList;
Activity activity;
OnImageClickListner listener;
OnImageLongClickListener longClickListener;
/*=============================================================== CONSTRUCTOR ===============================================================*/
public PhotosAdapter(Context context, ArrayList<ImageModel> arrayList, Activity activity, OnImageClickListner listner, OnImageLongClickListener longClickListener) {
this.context = context;
this.arrayList = arrayList;
this.activity = activity;
this.listener = listner;
this.longClickListener = longClickListener;
}
/*=============================================================== OVERRIDDEN METHODS ===============================================================*/
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { //This methods returns single_view.xml as a view for RecyclerView.
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.single_view, parent, false);
return new MyViewHolder(view, listener, longClickListener);
}
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position) { //Binding the uris with each view depending upon the position of current view.
activity.runOnUiThread(() -> GlideApp.with(context)
.load(Uri.parse(arrayList.get(position).getUri()))
.apply(RequestOptions.overrideOf(150, 150)) //It overrides the value of original image and reduces it to the visible thumbnail size.
.diskCacheStrategy(DiskCacheStrategy.RESOURCE) //Then it caches the reduced size thumbnail for faster loading speed.
.into(holder.img));
}
@Override
public int getItemCount() {
return arrayList.size();
}
/*=============================================================== INNER VIEW HOLDER CLASS ===============================================================*/
public static class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener {
private final ImageView img;
public CheckBox selection;
OnImageClickListner listener;
OnImageLongClickListener longClickListener;
public final SparseBooleanArray selectedItems; ///////////////////////////////// ADDED LINE /////////////////////////////////
public MyViewHolder(@NonNull View itemView, OnImageClickListner listener, OnImageLongClickListener longClickListener) {
super(itemView);
this.listener = listener;
this.longClickListener = longClickListener;
itemView.setOnLongClickListener(this); //onLongClickListener is set to all of the RecyclerView Items for once rather than setting on each item in BindViewHolder for repeated times
itemView.setOnClickListener(this); //onClickListener is set to all of the RecyclerView Items for once rather than setting on each item in BindViewHolder for repeated times
img = itemView.findViewById(R.id.img);
selection = itemView.findViewById(R.id.checkbox);
selectedItems = new SparseBooleanArray(); ///////////////////////////////// ADDED LINE /////////////////////////////////
}
@Override
public void onClick(View v) {
listener.onclick(getAdapterPosition(), selection); //Returning the current clicked position and selection checkbox to the implemented method.
}
@Override
public boolean onLongClick(View v) {
longClickListener.onLongClick(getAdapterPosition(), v); //Returning the current clicked position and view to the implemented method.
return true;
}
//////////////////////////////////////////////////////////////////////////// ADDED LINES ////////////////////////////////////////////////////////////////////////////
boolean isSelected(int position) {
return getSelectedItems().contains(position);
}
public void toggleSelection(int position) {
if (selectedItems.get(position, false)) {
selectedItems.delete(position);
} else {
selectedItems.put(position, true);
}
notifyItemChanged(position);
}
public void selectAll() {
for (int i = 0; i < getItemCount(); i++) {
if (!(selectedItems.get(i, false))) {
selectedItems.put(i, true);
}
notifyItemChanged(i);
}
notifyDataSetChanged();
}
public void clearSelection() {
List<Integer> selection = getSelectedItems();
selectedItems.clear();
for (Integer i : selection) {
notifyItemChanged(i);
}
}
public int getSelectedItemCount() {
return selectedItems.size();
}
public List<Integer> getSelectedItems() {
List<Integer> items = new ArrayList<>(selectedItems.size());
for (int i = 0; i < selectedItems.size(); ++i) {
items.add(selectedItems.keyAt(i));
}
return items;
}
} //INNER CLASS ENDS
/*=============================================================== INTERFACES ===============================================================*/
public interface OnImageClickListner { //Interface to generate call back when user clicked an image.
void onclick(int position, CheckBox selection);
}
public interface OnImageLongClickListener { //Interface to generate call back when user long clicked an image.
void onLongClick(int position, View v);
}
}
这就是导致双重或多重选择的原因。 Recyclerview 以这种方式工作,视图被回收。
因此您必须在每次展开视图时隐藏、选中或取消选中每个项目。
所以在 onbindViewholder
中,你必须 setChecked()
为 true 或 false,具体取决于你的情况。
我解决这个问题的方法是: 不要将视图传递给父片段,而是以这种方式在适配器中保留检查逻辑:
if (isItemSelected){
selection.setChecked(true);
}else{
selection.setChecked(false);
}
这样就可以完美的勾选和取消勾选了。
--更新--
创建Selectable适配器class提供isSelected()
方法如下
可选适配器
public abstract class SelectableAdapter<VH extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<VH> {
private static final String TAG = SelectableAdapter.class.getSimpleName();
private final SparseBooleanArray selectedItems;
SelectableAdapter() {
selectedItems = new SparseBooleanArray();
}
boolean isSelected(int position) {
return getSelectedItems().contains(position);
}
public void toggleSelection(int position) {
if (selectedItems.get(position, false)) {
selectedItems.delete(position);
} else {
selectedItems.put(position, true);
}
notifyItemChanged(position);
}
public void selectAll() {
for (int i = 0; i < getItemCount(); i++) {
if (!(selectedItems.get(i, false))) {
selectedItems.put(i, true);
}
notifyItemChanged(i);
}
notifyDataSetChanged();
}
public void clearSelection() {
List<Integer> selection = getSelectedItems();
selectedItems.clear();
for (Integer i : selection) {
notifyItemChanged(i);
}
}
public int getSelectedItemCount() {
return selectedItems.size();
}
public List<Integer> getSelectedItems() {
List<Integer> items = new ArrayList<>(selectedItems.size());
for (int i = 0; i < selectedItems.size(); ++i) {
items.add(selectedItems.keyAt(i));
}
return items;
}
}
让您的适配器扩展 selectableAdapter
如下:
适配器Class
public class RecyclerViewAdapter extends SelectableAdapter<RclAdapter.ViewHolder>
在片段上使用 toggleSelection
将位置设置为选中或未选中。
@Override
public void onclick(int position) {
if (!isSelectionMode) {
Intent intent = new Intent(getActivity(), FullPhoto.class);
intent.putExtra("uri", arrayList.get(position).getUri());
startActivity(intent);
}
else
{
// Use the adapter instance here
adapter.toggleSelection(position);
}
}
记住 toggleSelection
通知适配器并调用 onBindViewHolder
。
在适配器中:onBindViewHolder
实现选择逻辑以显示和隐藏复选框。
如果只设置为View.VISIBLE
,未选中的不设置为View.GONE
,还是一样的问题。