Android RecyclerView設定複数選択

28931 ワード

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には、複数選択、共有、削除、名前変更の4つのオプションがあります.後ろの3人は気にしないで、最初の多選だけを見ています.複数選択ボタンをクリックすると、下部のbottomDialogがdimissし、adapterにリフレッシュを促すと、すべてのitemのcheckBoxがVISIBLEと設定され、uncheckとなります.具体的な実装はmultipleDeleteFile()関数です.この関数をよく見てみましょう.1.まず変数ifMultipleにtrueを割り当て、adapterを更新します.ここでifMultipleをtrueに設定してからadapterをロードすると、onBindView Holder()関数では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関数を見て、dialogのように下部のカスタムpopupWindowFragmentをポップアップします.削除とキャンセルの2つのボタンがあります.ユーザーが一定数のitemを選択して削除をクリックすると、次のコードが実行されます.
    if (ifMultipleDeleteClicked){
         for (RecordingFiles recordings:multipleFileList){
               File tempFile= new File(fileDir,recordings.getFileName());
               if (tempFile.exists())tempFile.delete();
         }
         ifMultipleDeleteClicked=false;
    }

    MultipleFileListはグローバル変数で、選択したすべての録音ファイルを記録し、ここでリストを巡って選択したファイルを削除します.3.最後に、以下のコードを実行し、listをクリアし、ブロードキャスト更新recyclerViewを送信する
    multipleFileList.clear();
                    ifMultiple=false;
                    //      recycler view
                    Intent intent=new Intent(NOTIFY_RECYCLER_VIEW);
                    s.getContext().sendBroadcast(intent);