ActionBar / ActionMode

ActionMode

Following on from the recent series on basic ActionBar, we’ll now have a look at concept which can really make our ActionBar even more powerful: ActionMode.

ActionMode is a mechanism for changing the UI model in a contextual way. Some obvious example of this are when editing a message using the built-in messaging app:

Edit Message

Edit Message (ActionMode)

A long touch on the text changes the input mode to “Text Selection” mode which provides copy and paste functionality by changing the ActionBar.

Another example of how ActionMode can be employed is in the Gallery app. When in Grid View, long pressing a picture switches to a multiple selection mode:

Gallery

Gallery (ActionMode)

At first, glance this seems like quite a complex thing to do. If you have an Activity or Fragment which is working perfectly, then you want to add a second mode whereby all of your click listeners have to change behaviour seems rather tricky. ActionMode makes that a lot easier.

The key part of our ActionMode implementation is the implementation of ActionMode.Callback. This is an interface which wraps the lifecycle of the ActionMode, and so we can perform specific tasks at various times during the ActionMode lifecycle. To understand this better, consider the Gallery app example that we looked at earlier. In normal mode, clicking on an individual image will view that image full screen, but once the selection ActionMode is active that behaviour changes such that clicking on an image toggles its selection state instead.

This can be achieved quite easily by changing the click listener for the image in onCreateActionMode() of the ActionMode.Callback implementation, and resetting it back to the original click listener in onDestroyActionMode().

As well as changing the behaviour of other controls, ActionMode can also replace the current ActionBar while the ActionMode is active. This is done by inflating a new menu in the onCreateActionMode(). It’s worth pointing out that this new menu get’s some default behaviour added to it by the Android framework

The ActionMode callbacks also provide us with a custom menu selection listener. Normally clicking an ActionBar action will result in onOptionsItemSelected() being called on our Activity. However, when an ActionMode is active, some basic behaviour is added by the Framework – an “Up” affordance where the Up / Home button would usually be on the left hand side. Clicking this will automatically finish the ActionMode. Alternatively the ActionMode can be ended by simply calling ActionMode.finish().

Let’s add a very basic ActionMode implementation to the code that we used for the series on Basic ActionBar. First we’ll define our ActionBar menu in res/menu/actionmode.xml:

[xml]




[/xml]

This will give us a TextView item which we’ll assign a string to later, and a manual “Cancel” item which we’ll put in the overflow menu because of android:showAsAction="never". We’ll add a couple of strings to res/values/strings.xml:

[xml] Action Mode
Action Mode
[/xml]

Next we’ll add our ActionBar.Callback implementation in MainActivity:

[java] private ActionMode.Callback mCallback = new ActionMode.Callback()
{
@Override
public boolean onPrepareActionMode( ActionMode mode, Menu menu )
{
return false;
}
@Override
public void onDestroyActionMode( ActionMode mode )
{
// TODO Auto-generated method stub
}
@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;
}
@Override
public boolean onActionItemClicked( ActionMode mode, MenuItem item )
{
boolean ret = false;
if(item.getItemId() == R.id.actionmode_cancel)
{
mode.finish();
ret = true;
}
return ret;
}
};
[/java]

Here we inflate our new menu in onCreateActionMode, get a reference to the TextView, and set a string to it; and we put a click handler in for our manual “Cancel” option and put the necessary handler in to onActionItemClicked().

Finally, we add a new menu item to the existing menu at res/menu/main.xml:

[xml]
[/xml]

And finally add a handler to the existing onOptionsItemSelected() handler in MainActivity:

[java] else if( item.getItemId() == R.id.menu_actionmode)
{
startActionMode( mCallback );
ret = true;
}
[/java]

When we run this, we can activate the ActionMode by selecting this new menu item:

Enter ActionMode

This enters the ActionMode and displays the new ActionBar in place of the old one:

ActionMode

And we can exit the ActionMode by either clicking on the “tick” icon on the left, or selecting the “Cancel ActionMode” menu that we added:

Ending ActionMode

That concludes our quick look at ActionMode, which allows us to quickly switch to new contextual action modes, and is surprisingly easy to implement.

The source code for this article can be found here.

© 2012, Mark Allison. All rights reserved.

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

5 Comments

  1. Nice walkthrough with easy code. Thanks. Just one typo:
    Instead of “actionmode.xml”, it should have been “main.xml” (main menu xml file) in the below line:

    ‘Finally, we add a new menu item to the existing menu at “res/menu/actionmode.xml”:’

  2. But just works in Android API 11, right ?
    i would like put actionmode in app at android 2.2, so i’ll have create a customized actionmode in xml….

    1. Actionmode was introduced with the ActionBar so, you’re right, it’s API 11 and later. Having said that, it is included in ActionBarSherlock so you could always use that to get ActionMode in 2.2.

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.