10
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {

    case android.R.id.home:
        return true;

    case R.id.searchIcon:
        return true;

    case R.id.startRefresh:
        refreshItem = item;
        refresh();
        return true;
    case R.id.stopRefresh:

        if (refreshItem != null && refreshItem.getActionView() != null) {
            refreshItem.getActionView().clearAnimation();
            refreshItem.setActionView(null);
        }
        return true;
    default:
        return super.onOptionsItemSelected(item);
    }
}


public void refresh() {
    if (FeedActivity.this != null) {
        /*
         * Attach a rotating ImageView to the refresh item as an ActionView
         */
        LayoutInflater inflater = (LayoutInflater) FeedActivity.this
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        ImageView iv = (ImageView) inflater.inflate(
                R.layout.refresh_action_view, null);
        Animation rotation = AnimationUtils.loadAnimation(
                FeedActivity.this, R.anim.clockwise_refresh);
        rotation.setRepeatCount(Animation.INFINITE);
        iv.startAnimation(rotation);
        refreshItem.setActionView(iv);
    }
}

Before Clicking:

enter image description here

After Clicking:

enter image description here

Here the icon is being animated(rotating).

Problem:

why is it shifting to the left?

once it shifts to the left, the icon becomes non clickable and strangely the device back button also doesn't work

EDIT:

In comments below this answer:

Animated Icon for ActionItem

Jake Warton says if you are using a square and correct sized icon for the menu item, you wont get this weird behaviour, to someone who has the same problem.

But i am using a 32x32 image on a device which uses mdpi drawables. Which as stated there must work :(

Thank You

EDIT:

refresh_action_view.xml

<?xml version="1.0" encoding="utf-8"?>
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
    style="@style/Widget.Sherlock.ActionButton"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/ic_refresh" />

Custom Style i use in my app

<style name="My_solid_ActionBar" parent="@style/Widget.Sherlock.Light.ActionBar.Solid.Inverse">
    <item name="background">@drawable/ab_solid_My</item>
    <item name="backgroundStacked">@drawable/ab_stacked_solid_My</item>
    <item name="backgroundSplit">@drawable/ab_bottom_solid_My</item>
    <item name="progressBarStyle">@style/My_ProgressBar</item>
    <item name="android:background">@drawable/ab_solid_My</item>
    <item name="android:backgroundStacked">@drawable/ab_stacked_solid_My</item>
    <item name="android:backgroundSplit">@drawable/ab_bottom_solid_My</item>
    <item name="android:progressBarStyle">@style/My_ProgressBar</item>
</style>
Community
  • 1
  • 1
Archie.bpgc
  • 23,812
  • 38
  • 150
  • 226
  • FWIW, here is a project demonstrating your desired effect, in case it gives you any ideas: https://github.com/commonsguy/cw-omnibus/tree/master/Progress/ActionBar – CommonsWare Nov 24 '12 at 13:03
  • Yeah, i used your code and even now the progressbar(set as ActionView) moves to the left.And none of the other menu items work. – Archie.bpgc Dec 01 '12 at 07:33
  • You should post a complete sample project that demonstrates your problem. If in my sample linked to above, I make `about` be `always` and the first action bar item, my `refresh` one still works, without exhibiting the behavior that you describe. – CommonsWare Dec 07 '12 at 16:14
  • @Archie.bpgc I've created solution, maybe it can help you somehow: http://stackoverflow.com/a/14360958/492624 – Marek Sebera Jan 16 '13 at 14:48

2 Answers2

8

The issue is that you're not handling all menu inflation in onCreateOptionsMenu(). The basic logic for an ActionBar refresh animation I've seen used in apps with open source , for example Andlytics (and also used myself in projects), is to implement a boolean flag in onCreateOptionsMenu() to decide whether to show the refresh animation.

You can implement it like this: When your refresh() method is called, it sets the boolean isRefreshing flag to true and calls inValidateOptionsMenu() which 'behind the scene' calls onCreateOptionsMenu() to start the animation:

Inflate the menu in onCreateOptionsMenu(...):

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    menu.clear();
    super.onCreateOptionsMenu(menu, inflater);
    //inflate a menu which shows the non-animated refresh icon
    inflater.inflate(R.menu.my_ab_menu, menu);

    if (isRefreshing) {
        //if we're refreshing, show the animation
        MenuItem item = menu.findItem(R.id.refreshMenuItem);
        item.setActionView(R.layout.action_bar_indeterminate_progress);
        ImageView iv = (ImageView) item.getActionView().findViewById(R.id.loadingImageView);
        ((AnimationDrawable) iv.getDrawable()).start();
    }
}

Start animation like so:

 public void refresh(){
        isRefreshing = true;
        inValidateOptionsMenu();
    }

If you want the user to start the animation when he taps the refresh icon, do like this in onOptionsItemSelected():

case R.id.refreshMenuItem:
    isRefreshing = true;
    item.setActionView(R.layout.action_bar_indeterminate_progress);
    ImageView iv = (ImageView) item.getActionView().findViewById(R.id.loadingImageView);
    ((AnimationDrawable) iv.getDrawable()).start();
    //...

To stop the animation call:

isRefreshing = false;
invalidateOptionsMenu();

This code is from a Fragment so you may have to tweak if for an Activity, but I think it communicates the basic idea.

Gunnar Karlsson
  • 28,350
  • 10
  • 68
  • 71
  • But in all the examples i saw, there is nothing like **invalidateOptionsMenu();**. Like the example i have in the question and the 1 which CommonsWare posted in comments. Will try this though. – Archie.bpgc Dec 07 '12 at 05:55
  • There are different ways to accomplish the same effect. I found this approach simple to understand and debug. Have a look at the Andlytics app example. You can download it from the market and see how it works as a real world example. – Gunnar Karlsson Dec 07 '12 at 06:00
  • I've edited the answer to show how to deal with user-initiated refresh rather than only programmatically starting the refresh animation. You'd have to add checks whether it's already animating when the user taps etc... – Gunnar Karlsson Dec 07 '12 at 06:20
  • This works, I found [this post](http://stackoverflow.com/questions/7980293/how-do-i-get-action-buttons-with-custom-layouts-to-be-styled-like-standard-actio) useful for getting the action button's style to match the standard android style, otherwise spacing might change when the animation is started: style="@android:style/Widget.ActionButton" – Patrick McKinnon Feb 02 '13 at 23:39
  • This works perfectly but in Android versions < 4.0, the progress animation is not fluid. Which can be the problem? I use Holoeverywhere and ActionBarSherlock. – anonymous May 17 '13 at 16:35
0

I tried the exact same code you use and it works just fine for me. The only things that might be different are two things:

1) the refresh_action_view layout (here's mine for comparison):

<?xml version="1.0" encoding="utf-8"?>
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
    style="?attr/actionButtonStyle"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/ic_menu_refresh" />

2) The display options of your action bar (here's my styles.xml for comparison).

<resources>

<style name="AppTheme" parent="Theme.Sherlock.Light.DarkActionBar">
    <item name="android:actionBarStyle">@style/Widget.ActionBar</item>
    <item name="actionBarStyle">@style/Widget.ActionBar</item>
</style>

<style name="Widget.ActionBar" parent="Widget.Sherlock.Light.ActionBar.Solid.Inverse">
    <item name="android:displayOptions">showHome|useLogo|showCustom</item>
    <item name="displayOptions">showHome|useLogo|showCustom</item>
</style>

</resources>

Can you share yours as well?

Tas Morf
  • 3,065
  • 1
  • 12
  • 8