23

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?

Thanks

Ahmad
  • 69,608
  • 17
  • 111
  • 137
g123k
  • 3,748
  • 6
  • 42
  • 45

4 Answers4

25

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.

Ivan G.
  • 5,027
  • 2
  • 37
  • 65
  • 7
    The xml code for actionbar_refresh_progress does not properly center the ProgressBar like the refresh icon. Nevertheless, followed the link to the Google IO app and pulled directly their actionbar_indeterminate_progress.xml and it works wonders! https://code.google.com/p/iosched/source/browse/android/res/layout/actionbar_indeterminate_progress.xml – jcxavier Mar 25 '13 at 16:15
25

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.

adamp
  • 28,862
  • 9
  • 81
  • 69
8

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);

}
Cailean
  • 81
  • 1
  • 1
  • Perfect. Could you please show your refresh_icon.xml layout? Every time I inflate ImageView the button becomes unclickable after calling doRefresh(false, ...); – Ivan G. Oct 23 '12 at 19:05
  • Ive done it this way and almost everything works fine. Problem is my progressdialog doesnt animate. Gets visible, then invisible, but with no animation at all. Cant understand why. – Duqe Jan 31 '14 at 12:26
1

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

Ε Г И І И О
  • 11,199
  • 1
  • 48
  • 63