Question

I'm looking for a way to make it so that when the user switches tabs the contextual action bar that I have becomes invalid.

I have it set up so that the tabs are linked to Fragments and each one has a different contextual action bar. I'm thinking that there might be a way to do this within the onTabUnselected() method, but I'm not sure how to go about it.

Any help would be much appreciated.

package com.androidDev.taskmanager;

import java.util.ArrayList;
import java.util.Locale;

import android.app.ActionBar;
import android.app.FragmentTransaction;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.app.ListFragment;
import android.support.v4.view.ViewPager;
import android.util.SparseBooleanArray;
import android.view.ActionMode;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
import android.widget.Toast;

public class Home extends FragmentActivity implements ActionBar.TabListener {
    private SectionsPagerAdapter mSectionsPagerAdapter;
    private ViewPager mViewPager;
    public static Menu mainMenu;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_home);

        // Set up the action bar.
        final ActionBar actionBar = getActionBar();
        actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

        // Create the adapter that will return a fragment for each of the three
        // primary sections of the app.
        mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());

        // Set up the ViewPager with the sections adapter.
        mViewPager = (ViewPager) findViewById(R.id.pager);
        mViewPager.setAdapter(mSectionsPagerAdapter);

        // When swiping between different sections, select the corresponding
        // tab. We can also use ActionBar.Tab#select() to do this if we have
        // a reference to the Tab.
        mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
                    @Override
                    public void onPageSelected(int position) {
                        actionBar.setSelectedNavigationItem(position);
                    }
                });

        // For each of the sections in the app, add a tab to the action bar.
        for (int i = 0; i < mSectionsPagerAdapter.getCount(); i++) {
            // Create a tab with text corresponding to the page title defined by
            // the adapter. Also specify this Activity object, which implements
            // the TabListener interface, as the callback (listener) for when
            // this tab is selected.
            actionBar.addTab(actionBar.newTab().setText(mSectionsPagerAdapter.getPageTitle(i)).setTabListener(this));
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.home, menu);
        mainMenu = menu;
        return true;
    }




    @Override
    public void onTabSelected(ActionBar.Tab tab,
            FragmentTransaction fragmentTransaction) {
        // When the given tab is selected, switch to the corresponding page in
        // the ViewPager.
        mViewPager.setCurrentItem(tab.getPosition());
    }

    @Override
    public void onTabUnselected(ActionBar.Tab tab,FragmentTransaction fragmentTransaction) {
    }

    @Override
    public void onTabReselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
    }

    public class SectionsPagerAdapter extends FragmentPagerAdapter {

        public SectionsPagerAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public Fragment getItem(int position) {
            // getItem is called to instantiate the fragment for the given page.
            // Return a DummySectionFragment (defined as a static inner class
            // below) with the page number as its lone argument.
            if(position==0){
                Fragment fragment = new ViewTaskFragment();
                return fragment;
            }
            else {
                Fragment fragment = new ViewReminderFragment();
                return fragment;
            }
        }

        @Override
        public int getCount() {
            // Show 2 total pages.
            return 2;
        }

        @Override
        public CharSequence getPageTitle(int position) {
            Locale l = Locale.getDefault();
            switch (position) {
            case 0:
                return getString(R.string.title_tasks).toUpperCase(l);
            case 1:
                return getString(R.string.title_reminders).toUpperCase(l);
            }
            return null;
        }
    }

    public static class ViewTaskFragment extends ListFragment {
        private final boolean POST_HONEYCOMB = Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB;
        private SimpleCursorAdapter sca;
        private ListView lv;
        private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() {
            // Called when the action mode is created; startActionMode() was called
            @Override
            public boolean onCreateActionMode(ActionMode mode, Menu menu) {
                // Inflate a menu resource providing context menu items
                MenuInflater inflater = mode.getMenuInflater();
                inflater.inflate(R.menu.task_context_menu, menu);
                return true;
            }

            // Called each time the action mode is shown. Always called after onCreateActionMode, but
            // may be called multiple times if the mode is invalidated.
            @Override
            public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
                return false; // Return false if nothing is done
            }

            // Called when the user selects a contextual menu item
            @Override
            public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
                switch (item.getItemId()) {
                    case R.id.menu_delete:
                        MyDB db = new MyDB(getActivity());
                        SparseBooleanArray checked = lv.getCheckedItemPositions();
                        ArrayList<String> valueBuilder = new ArrayList<String>();
                        String[] values;
                        for (int i = 0; i < checked.size(); i++) {
                            if(checked.valueAt(i) == true) {
                                valueBuilder.add(String.valueOf(lv.getItemIdAtPosition(i)));
                            }
                        }
                        values = valueBuilder.toArray(new String[valueBuilder.size()]);
                        if(values!=null)
                            db.deleteTasks(values);
                        refreshListView();
                        mode.finish(); // Action picked, so close the CAB
                        return true;
                    default:
                        return false;
                }
            }
            // Called when the user exits the action mode
            @Override
            public void onDestroyActionMode(ActionMode mode) {
                lv.clearChoices();
                for (int i = 0; i < lv.getChildCount(); i++)
                    lv.setItemChecked(i, false);
                mode = null;
            }
        };
        public ViewTaskFragment() {}
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstaceState) {
            final View rootView = inflater.inflate(R.layout.view_task, container, false);
            Context context = getActivity();
            hasOptionsMenu();
            String[] from = {"_id", "task_name", "completion_date"};
            int[] to={R.id.rpt_task_id, R.id.rpt_task_name, R.id.rpt_completion_date};
            MyDB db = new MyDB(context);
            sca = new SimpleCursorAdapter(context, R.layout.task_item, db.selectTasks(), from, to, 0);
            lv = (ListView) rootView.findViewById(android.R.id.list);
            lv.setAdapter(sca);
            lv.setLongClickable(true);
            lv.setOnItemLongClickListener(new OnItemLongClickListener() {
                    public boolean onItemLongClick(AdapterView<?> parent, View v, int position, long id) {
                        Toast.makeText(getActivity(), "Running onItemLongClick Orig Code", Toast.LENGTH_SHORT).show();
                        if(POST_HONEYCOMB) {
                             getActivity(). startActionMode(mActionModeCallback);
                        }
                        else {
                            //Needs at least honeycomb
                        }
                        return true;
                    }
                });
            return rootView;
        }

        @Override
        public void onResume() {
            super.onResume();
            refreshListView();
        }
        public void refreshListView() {
            MyDB db = new MyDB(getActivity());
            sca.changeCursor(db.selectTasks());
        }

    }
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle item selection
        Intent intent = null;
        switch (item.getItemId()) {
        case R.id.mnu_action_settings:
            intent = new Intent(this, Settings.class);
            startActivity(intent);
            return true;
        case R.id.mnu_add_reminder:
            intent = new Intent(this, AddReminder.class);
            startActivity(intent);  
            return true;
        case R.id.mnu_add_task:
            intent = new Intent(this, AddTask.class);
            startActivity(intent);
            return true;
        default:
            return super.onOptionsItemSelected(item);
        }
    }
    /** New Fragment Section**/
    public static class ViewReminderFragment extends Fragment {
        private final boolean POST_HONEYCOMB = Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB;
        private SimpleCursorAdapter sca;
        private ListView lv;
        private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() {
            // Called when the action mode is created; startActionMode() was called
            @Override
            public boolean onCreateActionMode(ActionMode mode, Menu menu) {
                // Inflate a menu resource providing context menu items
                MenuInflater inflater = mode.getMenuInflater();
                inflater.inflate(R.menu.task_context_menu, menu);
                return true;
            }

            // Called each time the action mode is shown. Always called after onCreateActionMode, but
            // may be called multiple times if the mode is invalidated.
            @Override
            public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
                return false; // Return false if nothing is done
            }

            // Called when the user selects a contextual menu item
            @Override
            public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
                switch (item.getItemId()) {
                    case R.id.menu_delete:
                        refreshListView();
                        mode.finish(); // Action picked, so close the CAB
                        return true;
                    default:
                        return false;
                }
            }
            // Called when the user exits the action mode
            @Override
            public void onDestroyActionMode(ActionMode mode) {
                lv.clearChoices();
                for (int i = 0; i < lv.getChildCount(); i++)
                    lv.setItemChecked(i, false);
                mode = null;
            }
        };


        public ViewReminderFragment() {}
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstaceState) {
            final View rootView = inflater.inflate(R.layout.view_reminder, container, false);
            Context context = getActivity();
            hasOptionsMenu();
            String[] from = {"_id", "task_name", "reminder_date"};
            int[] to={R.id.rpt_task_id, R.id.rpt_task_name, R.id.rpt_reminder_date};
            MyDB db = new MyDB(context);
            sca = new SimpleCursorAdapter(context, R.layout.reminder_item, db.selectReminder(), from, to, 0);
            lv = (ListView) rootView.findViewById(R.id.reminderList);
            lv.setAdapter(sca);
            lv.setLongClickable(true);
            lv.setOnItemLongClickListener(new OnItemLongClickListener() {
                    public boolean onItemLongClick(AdapterView<?> parent, View v, int position, long id) {
                        if(POST_HONEYCOMB) {
                             getActivity(). startActionMode(mActionModeCallback);
                        }
                        else {
                            //Needs at least honeycomb
                        }
                        return true;
                    }
                });
            return rootView;
        }

        @Override
        public void onResume() {
            super.onResume();
            refreshListView();
        }
        public void refreshListView() {
            MyDB db = new MyDB(getActivity());
            sca.changeCursor(db.selectReminder());
        }
    }
Was it helpful?

Solution 2

So this is somewhat cheating in the way its being done, but it works.

I put this in the onTabUnselected() method.

        mViewPager.startActionMode(new ActionMode.Callback() {
        @Override
        public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
            // TODO Auto-generated method stub
            return false;
        }   
        @Override
        public void onDestroyActionMode(ActionMode mode) {
            // TODO Auto-generated method stub

        }   
        @Override
        public boolean onCreateActionMode(ActionMode mode, Menu menu) {
            // TODO Auto-generated method stub
            return false;
        }   
        @Override
        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
            // TODO Auto-generated method stub
            return false;
        }
    });

OTHER TIPS

I think I figured out an interesting way that's not "cheating".

First, I created a FragmentTabListener interface, so that the activity can let the tab fragments know when they've been selected or unselected.

public interface FragmentTabListener {
    public void onTabSelected();

    public void onTabUnselected();
}

Then, on the ActionBar.TabListener onTabUnselected() method, I can let each tab know when it's been selected or unselected.

ActionBar.TabListener tabListener = new ActionBar.TabListener() {

    @Override
    public void onTabUnselected(Tab tab, FragmentTransaction ft) {
        ((FragmentTabListener) MyFragmentForTab).onTabUnselected();
    }

I created a different listener because I didn't really want to expose other things to the tab, only the fact that it was selected or unselected. Also, the above is slightly pseudo-code to hide extraneous information.

Next, on the fragment used for the specific tab, I keep the actionMode whenever it's created (and delete it whenever it's destroyed)

@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
    // Inflate the menu for the CAB
    ...
    MyFragmentForTab.this.mActionMode = mode;
    return true;
}

@Override
public void onDestroyActionMode(ActionMode mode) {
    MyFragmentForTab.this.mActionMode = null;
}

Finally, when the tab is unselected, I just call

if (this.mActionMode != null)
    this.mActionMode.finish();

What about hide it?

 getActionBar().hide();

Or cheat. If tab is switch on ( boolean x=true). If true, use function for Action Bar. If x=false do nothing.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top