如何 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,还是一样的问题。