Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android NavigationView MenuItem Icon Animation

I'm trying to understand if menu icon animation should work in the new Navigationview, the same way action items animation works or any other view for that matter, that is used on any app layout.

The code below doesn't work for me. I'm using for testing the code sample released by Android for the new support library. Same animation code works nicely on the toolbar. Also tried the older API for animation (followed that link: Animated Icon for ActionItem)

I guess I'm missing something...

thanks ahead.

Code:

Xml:

<android.support.v4.widget.DrawerLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/drawer_layout"
    android:layout_height="match_parent"
    android:layout_width="match_parent"
    android:fitsSystemWindows="true"
    android:background="@color/lightPrimaryColor">

    <include layout="@layout/include_list_viewpager"/>

    <android.support.design.widget.NavigationView
        android:id="@+id/nav_view"
        android:layout_height="match_parent"
        android:layout_width="wrap_content"
        android:layout_gravity="start"
        android:fitsSystemWindows="true"
        android:background="@color/lightPrimaryColor"
        app:headerLayout="@layout/nav_header"
        app:theme="@style/menu_item_style"
        app:menu="@menu/drawer_view"/>

</android.support.v4.widget.DrawerLayout>

drawer_view:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:class="http://schemas.android.com/tools"
    class:actionViewClass="android.widget.ProgressBar">

    <group android:checkableBehavior="single"
        android:id="@+id/drawer_menu">
        <!--   <item
           android:id="@+id/nav_my_lists"
           android:title="@string/title_shopping_lists"
           android:icon="@drawable/ic_event"
           app:showAsAction="always"/> -->
        <item
            android:id="@+id/nav_examp_lists"
            android:icon="@drawable/refresh1"
            android:title="@string/example"
            app:showAsAction="always"
            android:layoutDirection="rtl"/>
        <item
            android:id="@+id/nav_split_lists"
            android:title="@string/split"
            android:icon="@drawable/refresh2"
            app:showAsAction="always"
            app:actionViewClass="android.widget.ImageView"/>
        <item
            android:id="@+id/nav_change_net"
            android:title="@string/change"
            android:icon="@drawable/refresh3"
            app:showAsAction="always"
            android:layoutDirection="rtl"/>

    </group>

</menu>

java:

navigationView.setNavigationItemSelectedListener(
                new NavigationView.OnNavigationItemSelectedListener() {
            @Override
            public boolean onNavigationItemSelected(MenuItem menuItem) {

               menuItem.setChecked(true);
               mDrawerLayout.closeDrawers();

                switch (menuItem.getItemId()) {

                    case R.id.nav_my_lists:

                        anim = AnimatorInflater.loadAnimator(getApplication(), R.animator.rotation);
                        anim.setTarget(menuItem.getIcon());
                        anim.setDuration(2000);
                        //anim.setStartDelay(10);
                        anim.addListener(new AnimatorListenerAdapter() {
                            @Override
                            public void onAnimationStart(Animator animation) {
                                Toast.makeText(getApplication(), "Started...", Toast.LENGTH_SHORT).show();
                            }

                        });

                        anim.start();
                        boolean run = anim.isRunning();

                        String title = menuItem.getTitle().toString();
                        loadShoppingList(title);

                        return true;
like image 903
user4970571 Avatar asked Nov 20 '22 22:11

user4970571


1 Answers

It is possible. You don't need set custom View for that.

private AnimationDrawableWrapper drawableWrapper;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    //...

    Menu menu = navigationView.getMenu();
    MenuItem menuItem = menu.findItem(R.id.your_icon);
    Drawable icon = menuItem.getIcon();
    drawableWrapper = new AnimationDrawableWrapper(getResources(), icon);
    menuItem.setIcon(drawableWrapper);
}

public void startRotateIconAnimation() {
    ValueAnimator animator = ObjectAnimator.ofInt(0, 360);
    animator.addUpdateListener(animation -> {
        int rotation = (int) animation.getAnimatedValue();
        drawableWrapper.setRotation(rotation);
    });
    animator.start();
}

We can't animate drawable directly, so use DrawableWrapper(from android.support.v7 for API<21):

public class AnimationDrawableWrapper extends DrawableWrapper {

    private float rotation;
    private Rect bounds;

    public AnimationDrawableWrapper(Resources resources, Drawable drawable) {
        super(vectorToBitmapDrawableIfNeeded(resources, drawable));
        bounds = new Rect();
    }

    @Override
    public void draw(Canvas canvas) {
        copyBounds(bounds);
        canvas.save();
        canvas.rotate(rotation, bounds.centerX(), bounds.centerY());
        super.draw(canvas);
        canvas.restore();
    }

    public void setRotation(float degrees) {
        this.rotation = degrees % 360;
        invalidateSelf();
    }

    /**
     * Workaround for issues related to vector drawables rotation and scaling:
     * https://code.google.com/p/android/issues/detail?id=192413
     * https://code.google.com/p/android/issues/detail?id=208453
     */
    private static Drawable vectorToBitmapDrawableIfNeeded(Resources resources, Drawable drawable) {
        if (drawable instanceof VectorDrawable) {
            Bitmap b = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
            Canvas c = new Canvas(b);
            drawable.setBounds(0, 0, c.getWidth(), c.getHeight());
            drawable.draw(c);
            drawable = new BitmapDrawable(resources, b);
        }
        return drawable;
    }
}

I took the idea for DrawableWrapper from here: https://stackoverflow.com/a/39108111/5541688

like image 78
Anrimian Avatar answered Mar 29 '23 13:03

Anrimian