我想在回收器 View 中选择多个项目,当选择它时,我想将该项目的复选框的可见性设置为可见。因此,我可以使用界面设置 onlongClickListner
并在 fragment 中处理 onLongClick
事件。
每当用户长按任何项目时,应用的 onCLick
逻辑就会发生变化。不久之后,单击应用程序将在另一个 Activity 中打开该项目,但是,长时间单击后,onClick
的逻辑发生了变化,可以设置我想要的任何内容。我想在长按后选中与该项目对应的复选框。并希望从回收器 View 中加载的 arrayList
添加该内容。
fragment
...
@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();
}
...
在这种情况下,我无法理解如何实现选择跟踪器。我可以使用 getAdapterPosition() 获取适配器位置,然后可以从该索引上的 arrayList 中删除元素。但是,我想突出显示该位置处的复选框。在这种情况下,我无法实现代码。
我尝试过的事情
我确实尝试从 onLongClick(View v)
传递 View v
,然后将 selection
复选框传递给 onCLick( )
事件。但是,没有成功。
我想从回收器 View 中选择项目,并将所选项目的可见性设置为 VISIBLE
。
------ 更新 ------
现在,我可以借助事件方法中的少量编辑将复选框的可见性设置为可见。
fragment
@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
类传递的复选框。但是,由于回收商观点的本质,我得到了双重选择。还有一个奇怪的问题是,在选择项目后,如果我向下滚动,选择将随机更改。
在此图像中,如您所见,我只选择了 4 个图像,但是当我向下滚动时,其他图像也被选择,当我再次向上滚动时,它弄乱了我选择的项目。
照片适配器
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 以这种方式工作, View 被回收。
因此,每次 View 膨胀时,您都必须隐藏、选中或取消选中每个项目。
因此,在 onbindViewholder
中,您必须根据您的场景将 setChecked()
设置为 true 或 false。
我解决这个问题的方法是: 不要将 View 传递给父 fragment ,而是以这种方式将检查逻辑保留在适配器中:
if (isItemSelected){
selection.setChecked(true);
}else{
selection.setChecked(false);
}
这样,就可以完美地检查和取消检查。
-- 更新 --
创建一个 Selectable 适配器类以提供 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
,如下所示:
适配器类
public class RecyclerViewAdapter extends SelectableAdapter<RclAdapter.ViewHolder>
在 fragment 上使用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
,您仍然会遇到同样的问题。
关于java - 如何在回收站 View android中选择多个项目?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68390421/