ActionBar / ActionMode

ActionBarCompat – Part 4

In the previous article we began converting our code to work with ActionBarCompat, but there are still some further changes required to get things working. In this article we’ll complete the code migration.

The next thing that we must do is change our ActionMode handling because ActionMode is unsurprisingly tied in to ActionBarCompat. Starting an ActionMode is simply a case of changing the method call to it’s support variant. So onOptionsItemSelected() changes from:

@Override
public boolean onOptionsItemSelected( MenuItem item )
{
	boolean ret;
	if (item.getItemId() == R.id.menu_settings)
	{
		// Handle Settings
		ret = true;
	} else if (item.getItemId() == R.id.menu_toggle)
	{
		ActionBar ab = getActionBar();
		if (ab.getNavigationMode() == ActionBar.NAVIGATION_MODE_TABS)
		{
			setListNavigation( ab );
			mSearchItem.setVisible( false );
		} else
		{
			setTabNavigation( ab );
			mSearchItem.setVisible( true );
		}
		ret = true;
	} else if( item.getItemId() == R.id.menu_actionmode)
	{
		startActionMode( mCallback );
		ret = true;
	} else
	{
		ret = super.onOptionsItemSelected( item );
	}
	return ret;
}

to:

@Override
public boolean onOptionsItemSelected( MenuItem item )
{
	boolean ret;
	if (item.getItemId() == R.id.menu_settings)
	{
		// Handle Settings
		ret = true;
	} else if (item.getItemId() == R.id.menu_toggle)
	{
		ActionBar ab = getActionBar();
		if (ab.getNavigationMode() == ActionBar.NAVIGATION_MODE_TABS)
		{
			setListNavigation( ab );
			mSearchItem.setVisible( false );
		} else
		{
			setTabNavigation( ab );
			mSearchItem.setVisible( true );
		}
		ret = true;
	} else if( item.getItemId() == R.id.menu_actionmode)
	{
		startSupportActionMode(mCallback);
		ret = true;
	} else
	{
		ret = super.onOptionsItemSelected( item );
	}
	return ret;
}

The next thing that we must do is change our ActionView implementation. The existing code for this is:

private ActionMode.Callback mCallback = new ActionMode.Callback()
{
	.
	.
	.
	@Override
	public boolean onCreateActionMode( ActionMode mode, Menu menu )
	{
		MenuInflater inflater = mode.getMenuInflater();
		inflater.inflate( R.menu.actionmode, menu );
		MenuItem item = menu.findItem( R.id.action_text );
		View v = item.getActionView();
		if( v instanceof TextView )
		{
			((TextView)v).setText( R.string.actionmode_title );
		}
		return true;
	}
	.
	.
	.
}

While the import change has already converted most of this, the highlighted line does not work because the getActionView() method was added in API 11 so is unavailable to us. We can get around this thanks to a utility class from the compat library named MenuItemCompat which provides implementations of some of the ActionProvider / ActionView related methods which were added in API 11. In our case, we need the getActionView() method, and this is implemented as a static method which takes a single, MenuItem argument:

View v = MenuItemCompat.getActionView(item);

The final thing that we need to do is change the layout resources that we use for our Spinner Adapters:

SimpleAdapter adapter = new SimpleAdapter( this, data,
	android.R.layout.simple_spinner_dropdown_item,
	new String[] { "title" }, new int[] { android.R.id.text1 } );

Instead of android.R.layout.simple_spinner_dropdown_item we should use a layout provided by the library:

SimpleAdapter adapter = new SimpleAdapter(
	getSupportActionBar().getThemedContext(), data,
	R.layout.support_simple_spinner_dropdown_item,
	new String[] { "title" }, new int[] { android.R.id.text1 } );

There is also a bug in the original code that we’re fixing here. We should be specifying a themed Context in the first argument of the SpinnerAdapter constructor, and we can obtain this from the support ActionBar implementation (Thanks to Chris Banes for pointing this out).

Our code migration to ActionBarCompat, and our project will now compile and run on devices back to API 7. However, things are not completely seamless and in the concluding article in this series we’ll compare things on different devices, and cover some of the differences that you should be aware of when using ActionBarCompat.

The source code for this article is available here.

© 2013 – 2014, Mark Allison. All rights reserved.

Copyright © 2013 Styling Android. All Rights Reserved.
Information about how to reuse or republish this work may be available at http://blog.stylingandroid.com/license-information.

3 Comments

  1. Hi.. When i run this project in Android API level 8. It crashes and i got the error like “java.lang.NoClassDefFoundError: com.stylingandroid.basicactionbar.MainActivity”

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.