Friday, January 17, 2014

Closing the Contextual Action Bar when switching to another Fragment

Been playing around in Android in my spare time when I encountered this... I have 3 Fragments listed in tab mode on the action bar:
  1. Fragment #3 is displayed, and has a contextual action bar shown from a long-press.
  2. Selecting Fragment #2 brings me to the page, but with the contextual action bar left over from Fragment #3.
 Clearly at this stage, I'd want the contextual action bar gone, but the results from Google were inconclusive. Fortunately, a bit of random checking in the documentation turned up onDestroy() in the Fragment class. There were hints and speculation suggesting the use of hide()/finish()/invalidate() and possibly applying them in the main Activity, from StackOverflow but I didn't find them exactly useful to my situation.

By chance, I decided to give one combination a shot, gave it a whirl and it seems to be working for me. It's surprisingly straightforward.

Here's my actionMode and its callBack:
    private ActionMode actionMode = null;
    private ActionMode.Callback actionModeCallBack = new ActionMode.Callback() {
       
        @Override
        public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
            return false;
        }
       
        @Override
        public void onDestroyActionMode(ActionMode mode) {
            try {
                for(int i=0;i<getListView().getCount();i++) {
                    getListView().setItemChecked(i, false);
                }
                updateHighlightsOnChecked();
                getListView().setChoiceMode(ListView.CHOICE_MODE_NONE);
            } catch(IllegalStateException e) {
                Log.d(app_name_tag, "ConfirmedFragment.actionModeCallBack.onDestroyActionMode IllegalStateException");
            }
            mode = null;
        }
       
        @Override
        public boolean onCreateActionMode(ActionMode mode, Menu menu) {
            MenuInflater inflater = mode.getMenuInflater();
            inflater.inflate(R.menu.confirmed_context_menu, menu);
            return true;
        }
       
        @Override
        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
            List<Integer> itemPositionList = new ArrayList<Integer>();
            Log.d(app_name_tag, "checked items: " + getListView().getCheckedItemCount());
            SparseBooleanArray bArr = getListView().getCheckedItemPositions();
            if(bArr != null) {
                for(int i=0;i<getListView().getCount();i++) {
                    if(bArr.get(i)) {
                        itemPositionList.add(i);
                    }
                }
            }
           
            switch(item.getItemId()) {
                case R.id.remove_confirmed:
                    callback.onConfirmedOrderRemoved(itemPositionList);
                    updateOrderList();
                    mode.finish();
                    return true;
            }
           
            return false;
        }
    };

The actionMode gets initiated in the long-click listener:
@Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
       
        getListView().setOnItemLongClickListener(new OnItemLongClickListener() {
           
            @Override
            public boolean onItemLongClick(AdapterView<?> adapterView, View view, int position, long id) {
                getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
                getListView().setItemChecked(position, true);
                updateHighlightsOnChecked();
                actionMode = getActivity().startActionMode(actionModeCallBack);
                view.setSelected(true);
                return true;
            }
        });
    }

And lastly, the most important part:

    @Override
    public void onDestroy() {
        super.onDestroy();
        if(actionMode != null)
            actionMode.finish();
    }

I figured since the contextual action bar (or pretty much everything else) would be wiped when the fragment gets swapped out, it can give the actionMode a holler to finish its business.

Give it a try and let me know if it works out for you.

No comments:

Post a Comment