As you have seen in the previous tutorials about ActionBarSherlock and the ActionBar, you can add action items easily and they show up either in the ActionBar itself or in the overflow menu.
But so far all you could add were normal action items. And those consisted either of icons, of text or of a combination of both - depending on the available space and of the way you configured the items to show up.
That's not always sufficient. Sometimes you would like to display a custom layout. And that's what ActionViews are for.
What are ActionViews
Action views allow to display arbitrary layouts instead of the usual icons or texts. They were introduced in Honeycomb together with the ActionBar.
Of course the available place for your layout limits your possibilities. Since - by a large margin - most Android devices are phones, your layout should take this into consideration.
With Ice Cream Sandwich ActionViews were improved further. Since then Android does not always display them fully expanded but allows for a collapsed mode as well. In this mode ActionViews show an icon as usual and only when the user clicks on the icon does it expand to the full layout.
When to use ActionViews
Basically you use ActionViews when you need to replace the icon with something else or when you need a more interactive widget.
Android itselfs comes bundled with the SearchView that adds an EditText
widget for search. I will cover this widget in the next section.
Another common use case is to replace an action item with a progress indicator when the action is bound to last longer. Most often this is used together with a refresh action item.
Using Android's SearchView
Android comes with the SearchView as the only bundled implementation of an ActionView.
I covered all you need to know about searching on Android and search suggestions in previous tutorials. Here I will cover only how to make use of the SearchView
.
Let me first show you some screenshots:
The first shows the action bar with the search icon - thus the action view is in collapsed mode. The second screenshot shows the view after the user has clicked on the icon. It expands to an EditText
widget together with the search hint of your searchable configuration. The microphone symbol is also the result of the search configuration file. The last screen shows the EditText
widget after the user has entered some characters.
If you have added search capabilities to your app, getting the SearchView
to support this is pretty easy. All you have to do is tell it about the search configuration. For this you need to get a SearchableInfo object from the SearchManager
and call setSearchableInfo()
with this object on the SearchView
object used for your ActionBar. Well for me code is often the best explanation, so here is what you have to do:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getSupportMenuInflater().
inflate(R.menu.activity_actionview, menu);
MenuItem item = menu.findItem(R.id.actionView);
SearchView searchView =
(SearchView)item.getActionView();
SearchManager searchManager =
(SearchManager)getSystemService(Context.SEARCH_SERVICE);
SearchableInfo info =
searchManager.getSearchableInfo(getComponentName());
searchView.setSearchableInfo(info);
return true;
}
You should understand most of it from my previous tutorial on ActionBarSherlock. New are the lines 6 to 11. These are where you add your search configuration to the SearchView
.
As you can see in the code above, I use the SearchView
together with ActionBarSherlock. ActionBarSherlock added a SearchView
with its 4.2 release. As a deviation from ABS' normal API level 7 support, the SearchView
only work from API level 8 onwards. The reason for this is that the SearchableInfo
interface was added with API level 8. So a support for a SearchView
prior to that makes no sense.
The version in ActionBarSherlock's 4.2 release had some problems with search suggestions. These were fixed by Matt Kranzler's accepted pull request to ABS. But this fix is currently only available in the dev branch of ActionBarSherlock.
Update: With the 4.3 release of ActionBarSherlock suggestions now work. So if you want to use them, you have to include ActionBarSherlock 4.3 (or any follow-up releases).
The next screenshot shows the suggestions provider at work with ActionBarSherlock's dev branch fixes on a 2.2 device:
Be very careful, if you use this branch. After all the current development is taking place here. It's not yet finalized for production!
A custom ActionView
As mentioned you can also create arbitrary action views. You have some options to do so:
- You can link to a layout file from within your
menu.xml
- You can set the layout when the action item is clicked
- You can write a custom View implementation
I do not cover the last one. That's because it's the least likely solution for you and also because I haven't yet covered how to create custom views in Android in this blog.
So let me show you how to use the first two.
Linking to a layout file
In this case you create a layout file and point to it directly from within your menu xml file:
<item
android:id="@+id/actionViewLayout"
android:showAsAction="ifRoom|collapseActionView"
android:icon="@drawable/ic_action_add"
android:title="Add"
android:actionLayout="@layout/activity_actionview_edittext"
/>
In line six you can see how the layout is referenced directly from within the menu item definition.
You still have the option to show it in expanded or in collapsed mode right from the outset. Line three in the xml snippet above uses a collapsed mode at first. The difference becomes obvious in the next screenshots. The first set shows the item in collapsed mode first. When you press the add item, Android expands the layout and moves all other action items into the overflow menu.
If you use the layout expanded all the time, it's present all the time and takes up the place it needs. All other action items are visible - as long as some place is left for them. That's what you see in the next screenshot. This option is the most space-constrained option you have. If your ActionView is always expanded, you probably have not much room left for any other action items. That's the reason I use a landscape screenshot. So make sure you use the value ifRoom
for the android:showAsAction
attributes of all the other items - and to limit the action view to as little space as absolutely necessary.
To use the expanded view all the time you simply have to remove the collapseActionView
value and the pipe symbol from line 3 of above's xml snippet.
Of course it depends on the use case at hand and what your layout is, but I think this option generally is best used with an expanded layout all the time. Otherwise users might get confused by the disappearing action items when they expand the layout. And users might not know that they can use the back button to collapse the view again. If you plan to expand the layout on an action item click you're probably better off with the option of the next paragraph.
Setting the layout when the user clicks the item
This option combines both methods of the former paragraph. Once again two screenshots demonstrate best what I am talking about:
The first screenshot shows the refresh icon as a normal action item. The layout file looks like any other menu item:
<item
android:id="@+id/progress"
android:icon="@drawable/ic_action_reload"
android:showAsAction="ifRoom"
android:title="@string/progress"
/>
But as soon as you click the refresh button, Android replaces it with the progress spinner. That's because I set an action view in reaction to the action item click. The first code shows the onOptionsItemSelected()
method in which I react to the item click:
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.progress) {
new DummyAsyncTask().execute((Void[])null);
return true;
}
return super.onOptionsItemSelected(item);
}
The AsyncTask is a sample implementation showing you how to change the action view values:
private class DummyAsyncTask extends
AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... params) {
// simulate doing some time-consuming stuff:
SystemClock.sleep(2000);
return null;
}
@Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
ActionViewActivity.this.mProgress.setActionView(null);
}
@Override
protected void onPreExecute() {
super.onPreExecute();
ActionViewActivity.this.mProgress.
setActionView(R.layout.activity_actionview_progress);
}
}
As soon as the work is done and the new values have been downloaded, you simply set the action view to null
again - in the code above I do this in the onPostExecute()
method.
As you can see it uses an expanded mode - but only for the time, the user actually needs this view. Do not use the value collapseActionView
in your menu item definition. Otherwise the layout expands on the left of the ActionBar and not in place of the icon!
Sample app
You can find the source of a sample app demonstrating all this on bitbucket. I'm more than happy if you spot any problems with the code and provide a pull request. You can also file an issue on the project page.
Lessons learned
In this tutorial you have seen how to make use of ActionViews. Very useful is the SearchView
- thus I detailed how to add this to your ActionBar and how to link it to your search configuration in this post.
You have also seen that in the current 4.2 release of ActionBarSherlock SearchSuggestions are not yet working correctly. But thanks to a fix those will be part of the next ABS release.
Finally you learned how to create an ActionView on your own, though use cases for this are limited. Probably the most common one is replacing an update icon with the progress spinner widget.