如何在回收站视图android中选择多个项目? [英] How to select multiple items in recycler view android?

查看:34
本文介绍了如何在回收站视图android中选择多个项目?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I want to select multiple items in recycler view and when it is selected I want to set visibility as visible of a checkbox of that item. So, long I am able to set onlongClickListner using interface and handling onLongClick event in a fragment.

每当用户长按任何项目时,应用程序的 onCLick 逻辑就会改变.在长按应用程序在另一个活动中打开该项目之前,但是,长按 onClick 后的逻辑已更改,可以根据需要进行设置.我想在长按后选中该项目对应的复选框.并想从一个在回收器视图中加载的 arrayList 添加它.

Whenever user performes long click on any item, app's onCLick logic is changed. Before long click app is opening the item in another activity but, after long click onClick's logic is changed and can be set whatever I want. I want to check the checkbox corresponding to the item after long click. And want to add that from an arrayList which is loaded in recycler view.

片段

...
@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 处的复选框.在这种情况下,我无法实现代码.

I this scenario, i am unable to understand how to implement a selection tracker. I can get the adapter position with getAdapterPosition() and then I can remove the element from arrayList on that index. But, I want to highlight the checkbox at that position. In this case i am unable to implement the code.

我尝试过的事情

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

I did try to pass the View v from onLongClick(View v) and then passing the selection checkbox to onCLick() event. But, It didn't work.

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

I want to select the items from recycler view and set visibility as VISIBLE for the selected Items.

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

------ Update ------

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

I am now able to set visibility of the checkbox as visible with the help of few edits in event methods.

片段

@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 类传递的复选框.但是,由于回收者视图的性质,我得到了双重选择.还有一个奇怪的问题,如果我向下滚动选择项目后,选择将随机更改.

Where selection is a checkbox passed from MyViewHolder class from adapter. But, because nature of the recycler view i am getting double selections. and one weird issues that after selecting items if I scroll down, selections will be changed randomly.

在这张图片中,如您所见,我只选择了 4 张图片,但是当我向下滚动时,其他图片也被选中了,当我再次向上滚动时,它把我选择的项目弄乱了.

In this image as you can see, I only selected 4 images but, when I scrolled down, other images were selected as well and when I scrolled up again it messed my selected items.

照片适配器

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 以这种方式工作,即回收视图.

This is what is causing the double or multiple selections. Recyclerview works this way, that views are recycled.

因此,您必须隐藏、选中或取消选中每个视图膨胀的项目.因此,在 onbindViewholder 中,您必须根据您的情况将 setChecked() 设置为 true 或 false.

So you have to hide, check or uncheck each item everytine a view is inflated. So in the onbindViewholder you have to setChecked() to true or false depending on your scenario.

我解决这个问题的方法是:不要将视图传递给父片段,而是以这种方式在适配器中保留检查逻辑:

My approach for this problem would be: Instead of passing views to the parent fragment, keep the check logic in the adapter this way:

if (isItemSelected){
          selection.setChecked(true);
}else{
           selection.setChecked(false);
}

这样做,就会有完美的检查和取消检查.

By so doing, there will be perfect checking and unchecking.

-- 更新 --

创建Selectable适配器类,提供isSelected()方法如下

Create a Selectable adapter class to provide the isSelected() method as follows

可选适配器

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 如下:

Have your Adapter extend the selectableAdapter as follows:

适配器类

public class RecyclerViewAdapter extends SelectableAdapter<RclAdapter.ViewHolder> 

在片段上使用 toggleSelection 将位置设置为选中或未选中.

On the fragment use toggleSelection to set a position as selected or not Selected.

@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.

Remember toggleSelection notifies the adapter and calls onBindViewHolder.

在适配器中:onBindViewHolder 实现选择逻辑以显示和隐藏复选框.如果你只将它设置为View.VISIBLE,而不将它设置为View.GONE,那么你仍然会遇到同样的问题.

In the adapter: onBindViewHolder implement the selection logic to show and hide the checkbox. If you only set it to View.VISIBLE and don't set it to View.GONE for the ones not selected, you will still have the same problem.

这篇关于如何在回收站视图android中选择多个项目?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆