RecyclerView的多选模式

来源:互联网 发布:球球刷爱心软件 编辑:程序博客网 时间:2024/05/29 18:16

在ListView中实现多选并不困难,因为它是自带多选模式的,主要包括CHOICE_MODE_MULTIPLECHOICE_MODE_MULTIPLE_MODAL。如果你想要更深入的了解这两者是如何工作的。那么这篇文章是非常适合你的。

他们之间的区别大概就是CHOICE_MODE_MULTIPLE模式的特点在于他本身没有排斥性,在能选择item的情况下,也可以响应普通点击事件。

CHOICE_MODE_MULTIPLE_MODAL和CHOICE_MODE_MULTIPLE恰恰相反,他是对普通点击操作和多选操作是排斥的,一旦有一个item被选中,即进入到多选状态,item的onclick事件被屏蔽。这种排斥性也是他比CHOICE_MODE_MULTIPLE多了个MODAL的原因

我们也可以利用这个多选模式完成RecyclerView的多选。

这里写图片描述

使用库实现选择模式

首先,导入库。将以下行添加到您的build.gradle:

compile 'com.bignerdranch.android:recyclerview-multiselect:+'

接下来,创建一个MultiSelector实例。在我的示例应用程序中,我在我的Fragment添加如下代码:

public class SDTxtListActivity extends AppCompatActivity {    RecyclerView  recycler;    ArrayList<FileMsgModel> txtFiles;    private MultiSelector multiSelector = new MultiSelector();    ...    }

MultiSelector是管理多选的核心对象。但是,您必须告诉MultiSelector何时进入/离开选择模式。

MultiSelector multiSelector = new MultiSelector();multiSelector.setSelectable(true); // enter selection mode
MultiSelector multiSelector = new MultiSelector();multiSelector.setSelectable(false); // leave selection mode

当选择某一项时,您还必须将ViewHolder告诉MultiSelector。

MultiSelector multiSelector = new MultiSelector();multiSelector.setSelectable(true); // enter selection modemultiSelector.setSelected(myViewHolder, true); // set myViewHolder to selected

SwappingHolder

您的ViewHolder必须实现SelectableHolder界面。该库提供了一个名为SwappingHolder的默认实现,用于处理被选择/未选择的视觉效果。

public class TxtFileHodler extends SwappingHolder implements View.OnClickListener,View.OnLongClickListener{  //(1)        private FileMsgModel dm;        private TextView textView;        public TxtFileHodler(View itemView) {            super(itemView,multiSelector);  //(2)            textView = (TextView) itemView.findViewById(R.id.txtName);            itemView.setLongClickable(true);            itemView.setOnClickListener(this);            itemView.setOnLongClickListener(this);        }        public void bindView(FileMsgModel fm){            this.dm = fm;            String txtName = dm.getFileName();            textView.setText(txtName);        }        @Override        public void onClick(View view) {            ....        }        @Override        public boolean onLongClick(View view) {  //(6)            if(!multiSelector.isSelectable()){   //(3)                multiSelector.setSelectable(true);  //(4)                multiSelector.setSelected(TxtFileHodler.this,true);  //(5)                return true;            }            return false;        }    }

创建一个子类SwappingHolder(1)的ViewHolder。当选择/取消选择时,MultiSelector可以通过SelectableHolder接口与ViewHolder进行通信。因此,您必须在ViewHolder的构造函数(2)中将MultiSelector传递给SwappingHolder。确保MultiSelector尚未处于选择模式(3),然后进入选择模式(4)。最后选择项目(5)。在这个例子中,我们选择长按(6)进入选择模式。您可以决定什么触发选择模式。

在选择模式下单击项目时,还可以通知MultiSelector。但是,您只需在选择模式下通知MultiSelector。当不在选择模式时,您可以正常处理项目点击。

该库提供了一种名为tapSelection()的方便方法。如果MultiSelector处于选择模式,则此方法将切换项目的选定状态并返回true。如果MultiSelector未处于选择模式,则此方法返回false。

 public class TxtFileHodler extends SwappingHolder implements View.OnClickListener,View.OnLongClickListener{        private FileMsgModel dm;        private TextView textView;        public TxtFileHodler(View itemView) {            super(itemView,multiSelector);            textView = (TextView) itemView.findViewById(R.id.txtName);            itemView.setLongClickable(true);            itemView.setOnClickListener(this);            itemView.setOnLongClickListener(this);        }        public void bindView(FileMsgModel fm){            this.dm = fm;            String txtName = dm.getFileName();            textView.setText(txtName);        }        @Override        public void onClick(View view) {            if(!multiSelector.tapSelection(TxtFileHodler.this)){                selectTxt(dm);            }        }        ....    }

模拟多选模式

要获得CHOICE_MODE_MULTIPLE_MODAL同样的效果,您可以实现ActionMode.Callback。
但是,该库提供了一个名为ModalMultiSelectorCallback的抽象类。

private ModalMultiSelectorCallback mActionModeCallback         = new ModalMultiSelectorCallback(mMultiSelector) { // (1)    ...};private class TxtFileHodler extends SwappingHolder        implements View.OnClickListener, View.OnLongClickListener {    ...    @Override    public boolean onLongClick(View view) {        if (!mMultiSelector.isSelectable()) {            ((AppCompatActivity) getActivity()).startSupportActionMode(mActionModeCallback); // (2)            mMultiSelector.setSelectable(true);            mMultiSelector.setSelected(MyViewHolder.this, true);            return true;        }        return false;    }}

首先创建一个ModalMultiSelectorCallback的实例,传入你的MultiSelector(1)。然后在启动ActionMode(2)时将此回调传递到系统中。

ModalMultiSelectorCallback公开ActionMode.Callback界面中通常用于创建/准备/响应/销毁ActionMode菜单项的所有方法:

public boolean onCreateActionMode(ActionMode mode, Menu menu);public boolean onPrepareActionMode(ActionMode mode, Menu menu);public boolean onActionItemClicked(ActionMode mode, MenuItem item);public void onDestroyActionMode(ActionMode mode);

对于这个例子,我们使用想要在选择模式中这样做:

private ModalMultiSelectorCallback mActionModeCallback = new ModalMultiSelectorCallback(multiSelector) {           /**            *  actionmode的菜单处理            * 进入多选模式后,ActionBar/ToolBar上会弹出一个菜单,这个菜单需要我们自定义            *            */        @Override        public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {            MenuInflater inflater = actionMode.getMenuInflater();            inflater.inflate(R.menu.sd_card_txt_menu,menu);            return true;        }        @Override        public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) {            return false;        }        //检查是否选中了某一项        @Override        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {            switch (item.getItemId()){                case R.id.action_delete:                    mode.finish();                    List<FileMsgModel> files =  new ArrayList<>();                for(int i = txtFiles.size()-1;i>=0;i--){                    if(multiSelector.isSelected(i,0)){ // (1)                            FileMsgModel fileModel = txtFiles.get(i);                            files.add(fileModel);                        }                    }                    Intent intent=new Intent();                    intent.putExtra("MESSAGE", (Serializable) files);                    setResult(2,intent);                    finish();                    multiSelector.clearSelections(); // (2)                    return true;                default:                    break;            }            return false;        }        /**          * 关闭多选模式          */        @Override        public void onDestroyActionMode(ActionMode actionMode) {            new TxtFileAdapter(txtFiles).clearSelections();        }    };
private class TxtFileAdapter extends RecyclerView.Adapter<TxtFileHodler> {        private ArrayList<FileMsgModel> files;        public TxtFileAdapter(ArrayList<FileMsgModel> txtFiles) {            this.files = txtFiles;        }        @Override        public TxtFileHodler onCreateViewHolder(ViewGroup parent, int viewType) {            LayoutInflater inflater = LayoutInflater.from(SDTxtListActivity.this);            View view = inflater.inflate(R.layout.item,parent,false);            return new TxtFileHodler(view);        }        @Override        public void onBindViewHolder(TxtFileHodler holder, int position) {            FileMsgModel txt = files.get(position);    //我们可以用这行代码替换选中后的背景                holder.setSelectionModeBackgroundDrawable(getResources().getDrawable(R.drawable.sd_txt_back_drawable));            holder.bindView(txt);        }        @Override        public int getItemCount() {            return files.size();        }        //关闭Model        public void clearSelections() {            multiSelector.setSelectable(false);            notifyDataSetChanged();        }    }

我们可以访问每个选定的项目(1)并对其做处理。完成对所有项目的操作后,还需要清除选择(2)。

原创粉丝点击