Invalidates the context action bar when switching tabs
I’m looking for a way so that when the user switches tabs, the contextual action bar I have becomes ineffective.
I’ve set it up to link tabs to fragments, and each tab has a different contextual action bar. I guess there might be a way to do this in the onTabUnselected() method, but I’m not sure how.
Any help would be 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());
}
}
Solution
I
think I came up with an interesting way not to “cheat”.
First, I created a FragmentTabListener interface so that activities let tab fragments know when they are selected or unchecked.
public interface FragmentTabListener {
public void onTabSelected();
public void onTabUnselected();
}
Then, on the ActionBar.TabListener onTabUnselected() method, I can let each tab know when it is selected or unchecked.
ActionBar.TabListener tabListener = new ActionBar.TabListener() {
@Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
((FragmentTabListener) MyFragmentForTab).onTabUnselected();
}
I
created a different listener because I really don’t want to expose anything else to the tab, but only want to show the fact that it’s checked or not. In addition, the above is a slight pseudocode that hides irrelevant information.
Next, on the fragment used for a specific tab, I keep the actionMode when creating (and delete it on destroy).
@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, I only call when no tab is selected
if (this.mActionMode != null)
this.mActionMode.finish();