Android RecyclerView设置多选

Android RecyclerView设置多选

本篇文章记录如何使用recyclerView,通过适配器来实现recyclerView的多选。点击多选按钮时每个item后面会显示一个checkBox,取消时checkBox会隐藏。要点如下:

  • recyclerView+Adapter
  • 自定义view的dialog
  • 自定义的popupWindow

一、实现基本的recyclerView+Adapter

/**
 * Created by stephen on 17-8-12.
 * 文件列表recyclerView适配器
 */

public class RecordingsAdapter extends RecyclerView.Adapter {

    private List recordingFileList;
    private static List multipleFileList=new ArrayList<>();//多选选择的文件集合
    private SavedRecordingsFragment s;
    private boolean ifRenameClicked=false;
    private boolean ifDeleteClicked=false;
    private boolean ifMultipleDeleteClicked=false;
    private PopupWindowRename popupWindowRename;//重命名popupWindow
    private PopupWindowDelete popupWindowDelete;//确认删除popupWindow
    private MultipleDeletePopup multipleBottomDialog;//多选删除popupWindow
    private static final String PLAY_DIALOG="com.example.stephen.soundrecorder.action.PLAY_DIALOG";
    private static final String NOTIFY_RECYCLER_VIEW="com.example.stephen.soundrecorder.action.NOTIFY_RECYCLER_VIEW";
    //录音文件存储父路径
    final private File fileDir=new File(Environment.getExternalStorageDirectory(),"/RecordFile");

    private Dialog bottomDialog;//底部选择dialog(delete,rename,share,multiple)
    private boolean ifMultiple=false;//是否多选

    static class ViewHolder extends RecyclerView.ViewHolder{
        TextView fileName,fileLength,fileData;
        CheckBox checkBox;
        View view;

        public ViewHolder(View itemView) {
            super(itemView);
            view=itemView;
            fileName=(TextView) itemView.findViewById(R.id.name_recording_file);
            fileLength=(TextView)itemView.findViewById(R.id.length_recording_file);
            fileData=(TextView)itemView.findViewById(R.id.data_recording_file);
            checkBox=(CheckBox)itemView.findViewById(R.id.check_recording_file);
        }
    }

    public RecordingsAdapter(List list, SavedRecordingsFragment s) {
        this.recordingFileList =list;
        this.s=s;
    }

    /**
     * 按键响应,点击item播放录音
     * 长按item滑出底部dialog,选择删除/重命名操作
     * @param parent
     * @param viewType
     */
    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        final View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_item_recordings,parent,false);

        final ViewHolder viewHolder=new ViewHolder(view);
        viewHolder.view.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //若在多选删除情况下,点击item选择/取消checkbox,不能播放
                if (ifMultiple){
                    if (viewHolder.checkBox.isChecked()){
                        viewHolder.checkBox.setChecked(false);
                    }else viewHolder.checkBox.setChecked(true);
                    return;
                }
                int position = viewHolder.getAdapterPosition();
                RecordingFiles recordingFiles = recordingFileList.get(position);
                Gson gson=new Gson();
                String recordJsonStr= gson.toJson(recordingFiles);
                Intent intent = new Intent(PLAY_DIALOG);
                intent.putExtra("record_json",recordJsonStr);
                v.getContext().sendBroadcast(intent);
            }
        });
        viewHolder.view.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {
                if (!ifMultiple){
                    longClickListener(viewHolder);
                }
                return true;
            }
        });
        viewHolder.checkBox.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int selectedPosition = viewHolder.getAdapterPosition();
                RecordingFiles selectedRecordingFiles = recordingFileList.get(selectedPosition);
                if (viewHolder.checkBox.isChecked()){
                    //若被选中
                    multipleFileList.add(selectedRecordingFiles);
                }else {
                    multipleFileList.remove(selectedRecordingFiles);
                }
            }
        });

        return viewHolder;
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        RecordingFiles recordingFiles=recordingFileList.get(position);
        holder.fileData.setText(recordingFiles.getFileData());
        holder.fileName.setText(recordingFiles.getFileName());
        holder.fileLength.setText(CalculateDurationToTime.calTime(recordingFiles.getFileLength()));
        if (ifMultiple){
            holder.checkBox.setVisibility(View.VISIBLE);
            holder.checkBox.setChecked(false);
        }else {
            holder.checkBox.setVisibility(View.INVISIBLE);
        }

    }

    @Override
    public int getItemCount() {
        return recordingFileList.size();
    }

    private View.OnClickListener itemsOnClick =new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.popup_rename_ok:
                    ifRenameClicked=true;
                    popupWindowRename.dismiss();
                    break;
                case R.id.popup_rename_cancel:
                    ifRenameClicked=false;
                    popupWindowRename.dismiss();
                    break;
                case R.id.popup_delete_ok:
                    ifDeleteClicked=true;
                    popupWindowDelete.dismiss();
                    break;
                case R.id.popup_delete_cancel:
                    ifDeleteClicked=false;
                    popupWindowDelete.dismiss();
                    break;
                case R.id.cancel_multiple_recording_file:
                    multipleBottomDialog.dismiss();
                    break;
                case R.id.delete_multiple_recording_file:
                    ifMultipleDeleteClicked=true;
                    multipleBottomDialog.dismiss();
                default:
                    break;
            }
        }
    };
    //长按item弹出底部popuWindow
    private void longClickListener(ViewHolder viewHolder){
            int position = viewHolder.getAdapterPosition();
            final RecordingFiles recordingFiles = recordingFileList.get(position);//选中的文件
            bottomDialog=new Dialog(s.getContext(),R.style.BottomDialog);
            LinearLayout root=(LinearLayout)LayoutInflater.from(s.getContext()).inflate(R.layout.bottom_dialog,null);
            //初始化底部dialog视图,设置按键响应
            //分享按键
            root.findViewById(R.id.multiple_recording_file).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    multipleDeleteFile();
                }
            });
            //分享按键
            root.findViewById(R.id.share_recording_file).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    shareFile(new File(fileDir,recordingFiles.getFileName()));
                }
            });
            //删除按键
            root.findViewById(R.id.delete_recording_file).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    deleteFile(new File(fileDir,recordingFiles.getFileName()));
                }
            });
            //重命名按键
            root.findViewById(R.id.rename_recording_file).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    renameFile(new File(fileDir,recordingFiles.getFileName()));
                }
            });
            bottomDialog.setContentView(root);
            Window dialogWindow = bottomDialog.getWindow();
            dialogWindow.setGravity(Gravity.BOTTOM);
            WindowManager.LayoutParams lp = dialogWindow.getAttributes(); // 获取对话框当前的参数值
            lp.x = 0; // 新位置X坐标
            lp.y = 0; // 新位置Y坐标
            lp.width = (int) s.getContext().getResources().getDisplayMetrics().widthPixels; // 宽度
            root.measure(0, 0);
            lp.height = root.getMeasuredHeight();
            lp.alpha = 9f; // 透明度
            dialogWindow.setAttributes(lp);
            bottomDialog.show();
        }
    //删除多选的文件
    public void multipleDeleteFile(){
        bottomDialog.dismiss();//隐藏底部dialog
        ifMultiple=true;//设置多选框可见
        //发送广播更新recycler view
        Intent intent=new Intent(NOTIFY_RECYCLER_VIEW);
        s.getContext().sendBroadcast(intent);
        //弹出底部删除/取消选择框
        multipleBottomDialog=new MultipleDeletePopup(s.getContext(),itemsOnClick);
        multipleBottomDialog.showAtLocation(s.getView(),Gravity.BOTTOM,0,0);
        multipleBottomDialog.setOnDismissListener(new PopupWindow.OnDismissListener() {
            @Override
            public void onDismiss() {
                if (ifMultipleDeleteClicked){
                    for (RecordingFiles recordings:multipleFileList){
                        File tempFile= new File(fileDir,recordings.getFileName());
                        if (tempFile.exists())tempFile.delete();
                    }
                    ifMultipleDeleteClicked=false;
                }
                //清空multipleFileList
                multipleFileList.clear();
                ifMultiple=false;
                //发送广播更新recycler view
                Intent intent=new Intent(NOTIFY_RECYCLER_VIEW);
                s.getContext().sendBroadcast(intent);
            }
        });
    }
    //分享文件
    private void shareFile(File file){
        bottomDialog.dismiss();//隐藏底部dialog
        setWindowAlpha(0.6f);//设置背景模糊,需要使用getActivity().getWindow(),所以需要在adapter构造器中传入fragment实例
        Intent shareIntent = new Intent();
        shareIntent.setAction(Intent.ACTION_SEND);
        shareIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(file));
        shareIntent.setType("audio/mp4");
        s.getContext().startActivity(Intent.createChooser(shareIntent,"发送至"));
        setWindowAlpha(1f);
    }
    //删除文件
    private void deleteFile(final File file){
        bottomDialog.dismiss();//隐藏底部dialog
        popupWindowDelete=new PopupWindowDelete(s.getContext(),itemsOnClick,file.getName());
        popupWindowDelete.showAtLocation(s.getView(),Gravity.CENTER,0,0);
        //设置背景模糊,需要使用getActivity().getWindow(),所以需要在adapter构造器中传入fragment实例
        setWindowAlpha(0.6f);
        //bottomPopupWindow消失后恢复fragment透明度
        //并判断是否点击了确定按钮
        //若点击了,就执行删除文件操作
        popupWindowDelete.setOnDismissListener(new PopupWindow.OnDismissListener() {
            @Override
            public void onDismiss() {
                setWindowAlpha(1f);
                if (ifDeleteClicked){
                    if (file.exists()){
                        file.delete();
                        Toast.makeText(s.getContext(),file.getName()+"文件已删除!",Toast.LENGTH_SHORT).show();
                        //发送广播更新recycler view
                        Intent intent=new Intent(NOTIFY_RECYCLER_VIEW);
                        s.getContext().sendBroadcast(intent);
                    }
                    ifDeleteClicked=false;
                }
            }
        });
    }
    //重命名文件
    private void renameFile(final File file){
        bottomDialog.dismiss();
        popupWindowRename =new PopupWindowRename(s.getContext(),itemsOnClick,file.getName().substring(0,file.getName().length()-4));
        popupWindowRename.showAtLocation(s.getView(),Gravity.CENTER,0,0);
        //设置背景模糊,需要使用getActivity().getWindow(),所以需要在adapter构造器中传入fragment实例
        setWindowAlpha(0.6f);
        //bottomPopupWindow消失后恢复fragment透明度
        //并判断是否点击了确定按钮
        //若点击了,就执行重命名操作
        popupWindowRename.setOnDismissListener(new PopupWindow.OnDismissListener() {
            @Override
            public void onDismiss() {
                setWindowAlpha(1f);
                if (ifRenameClicked){
                    Log.d("RecorderAdapter",file.getAbsolutePath());
                    if (file.exists()){
                        Log.d("RecorderAdapter","file exist!!!");
                        File renameFile=new File(fileDir, popupWindowRename.getEditText()+".mp3");
                        file.renameTo(renameFile);
                        //发送广播更新recycler view
                        Intent intent=new Intent(NOTIFY_RECYCLER_VIEW);
                        s.getContext().sendBroadcast(intent);
                    }
                    ifRenameClicked=false;
                }
            }
        });
    }

    //设置fragment透明度
    private void setWindowAlpha(float f){
        WindowManager.LayoutParams lp=s.getActivity().getWindow().getAttributes();
        lp.alpha = f; //0.0-1.0
        s.getActivity().getWindow().setAttributes(lp);
    }
}

-以上是adapter的全部代码,先贴出来

二、下面详细讲解一下实现过程

首先,长按item时,会跳出一个底部dialog。既代码中的bottomDialog,这里有四个选项,分别为:多选、分享、删除和重命名。后面三个我们不去管,只看第一个多选。
点击多选按钮时,底部的bottomDialog会dimiss,这时提醒adapter刷新,所有item的checkBox会被设置称VISIBLE,且都是uncheck。具体实现在multipleDeleteFile()函数。
我们来仔细看一下这个函数:
1.首先给变量ifMultiple赋值为true,再更新adapter
这里设置ifMultiple为true后再去加载adapter时,我们看到在onBindViewHolder()函数里,会设置checkBox为VISIBLE,同时初始化为uncheck;

public void onBindViewHolder(ViewHolder holder, int position) {
        RecordingFiles recordingFiles=recordingFileList.get(position);
        holder.fileData.setText(recordingFiles.getFileData());
        holder.fileName.setText(recordingFiles.getFileName());
        holder.fileLength.setText(CalculateDurationToTime.calTime(recordingFiles.getFileLength()));
        if (ifMultiple){
            holder.checkBox.setVisibility(View.VISIBLE);
            holder.checkBox.setChecked(false);
        }else {
            holder.checkBox.setVisibility(View.INVISIBLE);
        }
    }

然后在onCreateViewHolder()函数中,设置item的点击响应事件,之前是点击就会播放这段录音,现在当ifMultiple为true时,点击item就会改变checkBox的选择状态并返回,也就是不会再播放录音来,同时长按item也不会有响应。

 @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        final View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_item_recordings,parent,false);

        final ViewHolder viewHolder=new ViewHolder(view);
        viewHolder.view.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //若在多选删除情况下,点击item选择/取消checkbox,不能播放
                if (ifMultiple){
                    if (viewHolder.checkBox.isChecked()){
                        viewHolder.checkBox.setChecked(false);
                    }else viewHolder.checkBox.setChecked(true);
                    return;
                }
                int position = viewHolder.getAdapterPosition();
                RecordingFiles recordingFiles = recordingFileList.get(position);
                Gson gson=new Gson();
                String recordJsonStr= gson.toJson(recordingFiles);
                Intent intent = new Intent(PLAY_DIALOG);
                intent.putExtra("record_json",recordJsonStr);
                v.getContext().sendBroadcast(intent);
            }
        });
        viewHolder.view.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {
              //若在多选删除情况下,长按item没有响应
                if (!ifMultiple){
                    longClickListener(viewHolder);
                }
                return true;
            }
        });
        viewHolder.checkBox.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int selectedPosition = viewHolder.getAdapterPosition();
                RecordingFiles selectedRecordingFiles = recordingFileList.get(selectedPosition);
                if (viewHolder.checkBox.isChecked()){
                    //若被选中
                    multipleFileList.add(selectedRecordingFiles);
                }else {
                    multipleFileList.remove(selectedRecordingFiles);
                }
            }
        });
        return viewHolder;
    }

2.我们接着看multipleDeleteFile函数,接下来弹出一个底部的自定义popupWindowFragment,类似于dialog,里面有两个按钮:删除和取消。当用户选择了一定数量的item后点击删除时,执行如下代码:

if (ifMultipleDeleteClicked){
     for (RecordingFiles recordings:multipleFileList){
           File tempFile= new File(fileDir,recordings.getFileName());
           if (tempFile.exists())tempFile.delete();
     }
     ifMultipleDeleteClicked=false;
}

multipleFileList是一个全局变量,他会记录所有被选中的录音文件,然后在这里遍历这个list删除选中的文件。
3.最后在执行如下代码,清空list并发送广播更新recyclerView

multipleFileList.clear();
                ifMultiple=false;
                //发送广播更新recycler view
                Intent intent=new Intent(NOTIFY_RECYCLER_VIEW);
                s.getContext().sendBroadcast(intent);

你可能感兴趣的:(android)