7

I have a menu item with an icon (imagine for example a clock with a single lancet), I would like to make its icon rotate indefinitely.

How could I manage this effect? Thank you.

madx
  • 6,723
  • 4
  • 55
  • 59
  • You can use Indeterminate progress bar : http://developer.android.com/reference/android/widget/ProgressBar.html#attr_android:indeterminate – shivamDev31 Mar 03 '15 at 19:59
  • Can I use it also to make a custom icon rotate? – madx Mar 03 '15 at 20:00
  • Ohh you want to rotate custom icon... I think you can... let me check if I get something for you – shivamDev31 Mar 03 '15 at 20:02
  • I think this will work : http://stackoverflow.com/questions/9162481/styling-indeterminate-progressbar-on-actionbar not sure though so there is no harm in trying. – shivamDev31 Mar 03 '15 at 20:05

2 Answers2

23

Add a file res/layout/iv_refresh.xml (replace ic_launcher with your custom icon):

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

Add a file res/anim/rotate_refresh.xml:

<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"
    android:fromDegrees="0"
    android:interpolator="@android:anim/linear_interpolator"
    android:pivotX="50%"
    android:pivotY="50%"
    android:toDegrees="360">
</rotate>

Finally in your java code you can start the animation like this:

LayoutInflater inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
ImageView iv = (ImageView)inflater.inflate(R.layout.iv_refresh, null);
Animation rotation = AnimationUtils.loadAnimation(this, R.anim.rotate_refresh);
rotation.setRepeatCount(Animation.INFINITE);
iv.startAnimation(rotation);
menu.findItem(R.id.my_menu_item_id).setActionView(iv);
madx
  • 6,723
  • 4
  • 55
  • 59
Jesson Atherton
  • 644
  • 7
  • 21
  • 3
    But how to set this for menu item? – Apurva Mar 03 '15 at 20:06
  • Get your view and assign the animation – Jesson Atherton Mar 03 '15 at 20:07
  • http://stackoverflow.com/questions/8614293/android-get-view-reference-to-a-menu-item this may be of use – Jesson Atherton Mar 03 '15 at 20:10
  • I tried with this: `((View)menu.findItem(R.id.my_menu_item_id)).startAnimation(mAnimation);` but I got this: `java.lang.ClassCastException: android.support.v7.internal.view.menu.m cannot be cast to android.view.View` – madx Mar 03 '15 at 20:24
  • Could you provide an example where you show how to do this? – madx Mar 03 '15 at 20:25
  • I just threw this together and it worked for me http://androidblog.reindustries.com/animating-update-or-loading-refresh-actionbar-button/ – Jesson Atherton Mar 03 '15 at 20:49
  • Ok this link explains it very well, let me completely rewrite your answer, so I can accept it... – madx Mar 03 '15 at 21:30
  • Haha my answer works very well in my app, but I'm using toolbar. – Jesson Atherton Mar 03 '15 at 21:34
  • If you don't accept the edits I should add my edited answer below so that everyone in the future could read it... let me know... – madx Mar 03 '15 at 21:50
  • My app using Toolbar, how to stop it? I just want rotate icon when refreshing data. It's possible? I can't stop with set menu item icon with drawable. – Sucipto May 14 '16 at 17:52
  • without cutom imageview? i set image in menu item xml `android:icon="@drawable/ic_refresh"` – user25 Mar 24 '18 at 15:56
  • for some reason doing this messes with the width/height and i cant seem to fix it. The original drawable has a different size than the set actionview one which looks really odd sadly. – Gereon99 Jul 10 '20 at 22:06
  • Finally!! A solution I was looking for a long time. Thank you!! – Amit Jayant Dec 09 '21 at 12:56
2

the best way is here:

public class HomeActivity extends AppCompatActivity {
    public static ActionMenuItemView btsync;
    public static RotateAnimation rotateAnimation;

@Override
protected void onCreate(Bundle savedInstanceState) {
    rotateAnimation = new RotateAnimation(360, 0, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
    rotateAnimation.setDuration((long) 2*500);
    rotateAnimation.setRepeatCount(Animation.INFINITE);

and then:

private void sync() {
    btsync = this.findViewById(R.id.action_sync); //remember that u cant access this view at onCreate() or onStart() or onResume() or onPostResume() or onPostCreate() or onCreateOptionsMenu() or onPrepareOptionsMenu()
    if (isSyncServiceRunning(HomeActivity.this)) {
        showConfirmStopDialog();
    } else {
        if (btsync != null) {
            btsync.startAnimation(rotateAnimation);
        }
        Context context = getApplicationContext();
        context.startService(new Intent(context, SyncService.class));
    }
}

Remember that u cant access "btsync = this.findViewById(R.id.action_sync);" at onCreate() or onStart() or onResume() or onPostResume() or onPostCreate() or onCreateOptionsMenu() or onPrepareOptionsMenu() if u want get it just after activity start put it in a postdelayed:

public static void refreshSync(Activity context) {
    Handler handler = new Handler(Looper.getMainLooper());
    handler.postDelayed(new Runnable() {
        public void run() {
            btsync = context.findViewById(R.id.action_sync);
            if (btsync != null && isSyncServiceRunning(context)) {
                btsync.startAnimation(rotateAnimation);
            } else if (btsync != null) {
                btsync.clearAnimation();
            }
        }
    }, 1000);
}
M Kasesang
  • 49
  • 4