Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Stop ExpandableListView groups expanding while Contextual Action Bar is visible

I have a fragment which contains an ExpandableListView. I would like to be able to select and delete items by group. I would also like to be able to select multiple group items for deletion, via a contextual action bar.

So far, I can click on groups to view children, and I can click on children to go to another Activity. I set the choice mode of the ExpandableListView to be CHOICE_MODE_MULTIPLE_MODAL, and it If I long click on a group, it is selected, a contextual action bar appears. If I select my delete button, the item is deleted. All good.

However, the problem arises when I attempt to select multiple groups in the CAB mode. It just doesn't work. If I click a second group, that group is expanded (not selected). I want to be able to just highlight multiple group items without any expansion occurring.

There's quite a lot of code to get this working, but I'll try to show some pertinent bits. The main issue is getting a list of selected group items. Secondarily, I don't want the groups to be expanded as they're selected (whilst the CAB is visible - this is what I am attempting by holding onto the ActionMode in mActionMode).

Any help is greatly appreciated.

ex.setMultiChoiceModeListener(new AbsListView.MultiChoiceModeListener() {
        @Override
        public void onItemCheckedStateChanged(ActionMode actionMode, int position, long id, boolean checked) {
            // Ignore long clicks on children
            long pos = ex.getExpandableListPosition(position);
            if (checked && (ExpandableListView.getPackedPositionType(pos) == ExpandableListView.PACKED_POSITION_TYPE_CHILD)) {
                ex.setItemChecked(position, false);
                return;
            }
        }

        @Override
        public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
            MenuInflater inflater = actionMode.getMenuInflater();
            inflater.inflate(R.menu.context_delete_items, menu);
            return true;
        }

        @Override
        public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) {
            mActionMode = actionMode;
            return false;
        }

        @Override
        public boolean onActionItemClicked(ActionMode actionMode, MenuItem item) {
            // If delete is clicked, delete the measurement set
            switch(item.getItemId()) {
                case(R.id.context_menu_delete_item):
                    Set<mySet> setsToDelete = new HashSet<mySet>();

                    if (ex != null) {
                        if (ex.getCheckedItemCount() > 0) {
                            SparseBooleanArray checkedPositions = ex.getCheckedItemPositions();
                            for (int i = 0; i < checkedPositions.size(); i++) {
                                int position = checkedPositions.keyAt(i);

                                /* Ignore selected children */
                                long pos = ex.getExpandableListPosition(position);
                                int groupPosition = ExpandableListView.getPackedPositionGroup(pos);


                                if (checkedPositions.valueAt(i)) {
                                    Log.d(TAG, "Adding MeasurementSet at position Key = " + position + " to deletion list");
                                    setsToDelete.add(mSets.get(groupPosition));
                                }

                            }
                        }
                    }

                    try {
                        if (ex != null && setsToDelete.size() > 0) {

                            ArrayList setsToDeleteList = new ArrayList(setsToDelete);
                            deleteSets(setsToDeleteList);

                            for (mySet s : setsToDelete) {
                                mSets.remove(s);
                            }

                            Toast.makeText(getActivity(), "Set deleted successfully", Toast.LENGTH_LONG).show();


                        }
                    } catch (SQLiteException sqlex) {
                        Log.e(TAG, "Delete operation failed");
                        Log.e(TAG, "Error was: " + sqlex.getMessage());
                        Log.e(TAG, "Stack trace: " + sqlex.getStackTrace());
                        Toast.makeText(getActivity(), "There was an error whilst deleting Set(s): " + sqlex.getMessage(), Toast.LENGTH_LONG).show();
                    }

                    actionMode.finish();
                    return true;
                default:
                    return false;
            }
        }

        @Override
        public void onDestroyActionMode(ActionMode actionMode) {
            mActionMode = null;
        }
    });

    ex.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
        @Override
        public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
            Long mId = mSets.get(groupPosition).getMyList().get(childPosition).getId();
            Intent intent = new Intent(getActivity(), ViewSingleActivity.class);
            intent.putExtra(getResources().getString(R.string.EXTRA_MID_KEY), measurementId);
            startActivityForResult(intent, Constants.REQ_VIEW_M);
            return true;
        }
    });

// Here I was trying to intercept group clicks and force the clicked group to collapse. Although this doesn't seem to solve the issue of having the group "selected"
    ex.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
        @Override
        public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {
            if (mActionMode != null) {
                Log.d(TAG, "mActionMode is not null. Setting View: " + parent.toString() + " to be selected");
                v.setSelected(true);
                Log.d(TAG, "Collapsing group " + groupPosition);
                parent.collapseGroup(groupPosition);
            }
            return false;
        }
    });
}
like image 696
mdhvn Avatar asked Jan 23 '14 14:01

mdhvn


1 Answers

Though this is an old post, figured I'd post an answer if anyone stumbled along. The problem is that the ExpandableListView does not support ChoiceMode. While it sorta seems to work and you can sorta manually call into the ExpandableListView to set items checked...it will never fully work right. For a more in depth reason on why; refer to this and this SO answer.

The OP did not specify if they wrote their own custom adapter or not. So I'll address both approaches.

If you wish to write your own custom ExpandableListAdapter, I suggest using the PatchedExpandabeListAdapter. You can read about it here. Basically it patches and improves upon some things...one of which is the ChoiceMode issue asked by the OP.

If you don't want to roll your own solution, there are two nice full fledged Rolodex adapters found here which implements the PatchedExpandabeListAdapter and most everything you need aside from the view generation.

like image 89
Jay Soyer Avatar answered Oct 07 '22 17:10

Jay Soyer