Stop ExpandableListView groups expanding while Contextual Action Bar is visible
Asked Answered
R

1

6

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;
        }
    });
}
Ribbon answered 23/1, 2014 at 14:0 Comment(6)
I seems that using parent.setItemChecked(groupPosition, true) inside onGroupClick() causes my group items to be selected, and allows me to delete multiple groups. Sadly, I still cannot 1) style the group to show it as selected (change background colour, etc.) 2) stop the group from expanding when it is clicked (only when the CAB is visible).Ribbon
Coincidentally I am currently working on the same task of combining ExpandableListView with Contextual Actionbar. For showing the group as selected, your group layout must use android:background="?android:attr/activatedBackgroundIndicator"Purchasable
Originally my group item root view was a <CheckedTextView> and this approach did not work. I changed it to be a <LinearLayout> containing a <TextView>, and now my group items show as selected! Thanks! But, is there some way to change the highlight colour? Thanks again.Ribbon
For anyone else wondering about this, it is well answered hereRibbon
Just to piggyback slightly: if anyone knows how to get a group item position (for checking/unchecking) regardless of whether groups are expanded or not, I would be much obliged. I can't get my head around all these packed positions, flat positions, etc.Ribbon
If you have the flat position elv.getExpandableListPosition(flatPosition) gives you the packed position. ExpandableListView.getPackedPositionGroup(packedPosition) gives you the group position regardless of expanded or not.Purchasable
P
1

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.

Pigskin answered 10/2, 2015 at 0:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.