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

问题描述 投票:0回答:1

我想在回收器视图中选择多个项目,当选择它时,我想将该项目的复选框的可见性设置为可见。所以,很长一段时间我都可以使用界面设置

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(), 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);
    }


}
java android android-recyclerview multipleselection
1个回答
2
投票

这就是导致双重或多重选择的原因。 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
,你仍然会遇到同样的问题。

© www.soinside.com 2019 - 2024. All rights reserved.