I would like to do the same thing than the GMail application on Honeycomb tablets. When you click on the Refresh button, the icon is replaced by a ProgressBar. How can I do this
Gmail does this using an action view for its "refresh in progress" state. Invoking a refresh is done using the standard action button/onMenuItemSelected path.
When you enter your refreshing state, set the action view of the refresh MenuItem to a ProgressBar. (Create it programmatically, inflate it from a layout, use actionLayout in the menu xml as CommonsWare suggests, whatever you prefer.) When you exit your refreshing state, set the action view back to null while keeping a reference to it so you can set it back again the next time you refresh. You can hang onto a reference to the MenuItem after you inflate the menu and changes to it later will be reflected in the action bar.
This approach has some advantages over using a full-time action view and managing other details of the state change yourself. An action view completely replaces the generated action button for a menu item, effectively blocking the user from being able to send the usual onMenuItemSelected events for refresh while a refresh is already in progress. One less thing to handle and the action view can stay completely non-interactive.
You could probably do something clever with an ActionProvider in API 14+ to encapsulate the whole process a bit more but the above ends up being pretty simple.
Ok, I tried what Cailean suggested but it didn't work for me. Every time I want to revert indeterminate progress to the original button it becomes unclickable, I used this layout for the progress
(actionbar_refresh_progress.xml)
<?xml version="1.0" encoding="utf-8"?>
<ProgressBar xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_gravity="center"/>
and this one to revert to the button
(actionbar_refresh_button.xml)
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:src="@drawable/ic_menu_refresh_holo_light"
android:layout_height="wrap_content"
android:layout_width="wrap_content"/>
my code was:
private void setRefreshing(boolean refreshing) {
this.refreshing = refreshing;
if(refreshMenuItem == null) return;
View refreshView;
LayoutInflater inflater = (LayoutInflater)getActionBar().getThemedContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if(refreshing)
refreshView = inflater.inflate(R.layout.actionbar_refresh_progress, null);
else
refreshView = inflater.inflate(R.layout.actionbar_refresh_button, null);
refreshMenuItem.setActionView(refreshView);
}
After browsing the source of the Google IO app, especially this file: http://code.google.com/p/iosched/source/browse/android/src/com/google/android/apps/iosched/ui/HomeActivity.java i found another easier way.
Now I need only the first layout with progress and the working method looks like this:
private void setRefreshing(boolean refreshing) {
this.refreshing = refreshing;
if(refreshMenuItem == null) return;
if(refreshing)
refreshMenuItem.setActionView(R.layout.actionbar_refresh_progress);
else
refreshMenuItem.setActionView(null);
}
Menu item definition:
<item android:id="@+id/mail_refresh"
android:title="Refresh"
android:icon="@drawable/ic_menu_refresh_holo_light"
android:showAsAction="always"/>
I hope someone finds this useful.
Use the following layout as the action view for the action bar menu item.
actionbar_refresh_progress.xml
<FrameLayout
android:layout_height="wrap_content"
android:layout_width="@dimen/abc_action_button_min_width"
android:minWidth="@dimen/abc_action_button_min_width">
<ProgressBar
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_gravity="center"
style="?indeterminateProgressStyle" />
</FrameLayout>
Then
menuItem.setActionView(R.layout.actionbar_refresh_progress);
Works across Gingerbread and the rest like a charm. Note that I have used dimension from support action bar for compatibility. You can use @dimen/action_button_min_width
instead for ICS and up.
Source: https://code.google.com/p/iosched/source/browse/android/res/layout/actionbar_indeterminate_progress.xml?r=f4fd7504d43b25a75cc23b58d6f844f3553b48c3
Assuming that you already have your menu item setup, you'll need to start by creating two new layouts. One that contains the layout for the normal refresh button, and another that contains the progressbar.
Once you have them, call the following piece of code to switch between the two layouts. It'll be up to you to decide exactly when it needs to be called a second time in order to switch it back to the refresh icon.
private void doRefresh(Boolean refreshing, MenuItem menuItem)
{
View refreshView;
LayoutInflater inflater = (LayoutInflater) getActionBar().getThemedContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if(refreshing)
refreshView = inflater.inflate(R.layout.actionbar_indeterminate_progress, null);
else
refreshView = inflater.inflate(R.layout.refresh_icon, null);
menuItem.setActionView(refreshView);
}