如何在回收站视图android中选择多个项目?

问题描述

我想在回收站视图中选择多个项目,当它被选中时,我想将可见性设置为该项目的复选框可见。因此,我能够使用接口设置 onlongClickListner 并在片段中处理 onLongClick 事件。

每当用户长按任何项目时,应用程序的 onCLick 逻辑就会改变。长按应用程序在另一个活动中打开该项目之前,但长按 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();
    }

...

在这种情况下,我无法理解如何实现选择跟踪器。我可以使用 getAdapterPosition() 获取适配器位置,然后我可以从该索引上的 arrayList 中删除元素。但是,我想突出显示 position 处的复选框。在这种情况下,我无法实现代码。

我尝试过的事情

我确实尝试从 View v 传递 onLongClick(View v),然后将 selection 复选框传递给 onCLick() 事件。但是,它没有用。

我想从回收商视图中选择项目并将所选项目的可见性设置为 VISIBLE

------ 更新 ------

我现在可以借助事件方法中的少量编辑将复选框的可见性设置为可见。

片段

@Override
    public void onclick(int position,CheckBox selection) {
        if (!isSelectionMode) {
            Intent intent = new Intent(getActivity(),arrayList.get(position).getUri());
            startActivity(intent);
        }
        else
        {
            selection.setVisibility(View.VISIBLE);
            selection.setChecked(true);
        }
    }

其中 selection 是从适配器的 MyViewHolder 类传递的复选框。但是,由于回收者视图的性质,我得到了双重选择。还有一个奇怪的问题,如果我向下滚动选择项目后,选择将随机更改。

Issue

在这张图片中,如您所见,我只选择了 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,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适配器类来提供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> 

在片段上使用 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,您仍然会遇到同样的问题。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...