9

I find a lot of questions about how to disable the animation of an Android ActionBar. I have exactly the opposite problem. I do want the animation but it should work out of the box right?

I think the problem lies with my custom toolbar:

<android.support.design.widget.AppBarLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_height="wrap_content"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/toolbar_parent"
    android:layout_width="match_parent"
    android:theme="@style/AppTheme.AppBarOverlay">

    <android.support.v7.widget.Toolbar android:id="@+id/toolbar"
        android:layout_width="match_parent" android:layout_height="@dimen/menu_height"
        android:minHeight="@dimen/menu_height"
        android:background="@color/backgroundColor" app:popupTheme="@style/AppTheme.PopupOverlay"
        android:theme="@style/ToolbarColoredBackArrow"/>

</android.support.design.widget.AppBarLayout>

Which I set in mij activity like so:

 Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
 setSupportActionBar(toolbar);

The toolbar works fine, but no animation when I call either of these methods:

protected void hideActionBar(){
    ActionBar ab = getSupportActionBar();
    if (ab.isShowing()) {
        ab.hide();
    }

}

protected void showActionBar(){
    ActionBar ab = getSupportActionBar();
    if (!ab.isShowing()) {
        ab.show();
    }
}

What is the reason of this?

Bart Burg
  • 4,786
  • 7
  • 52
  • 87
  • This is a shot in the dark: you may have to explicitly enable the animations. Try `getSupportActionBar().setShowHideAnimationEnabled(true)`. Note that animated show & hide is only available on API 14 and up. – Vikram Nov 26 '15 at 10:07
  • I tried it before, it doesn't work. It should animate it by default anyway. Somewhere in this implementation I have something that blocks the animation, but where? – Bart Burg Nov 26 '15 at 10:14
  • @Bart Burg, what are you using - `ActionBar` or `ToolBar`? – Vladimir Markeev Nov 26 '15 at 13:04
  • @VladimirMarkeev, Toolbar, though I do set it: setSupportActionBar(toolbar); – Bart Burg Nov 26 '15 at 13:09
  • @Bart Burg, try to apply animation to `ToolBar` as Anoop M replied, follow this link - http://stackoverflow.com/questions/26539623/android-lollipop-toolbar-how-to-hide-show-the-toolbar-while-scrolling – Vladimir Markeev Nov 26 '15 at 13:52

5 Answers5

20

Please discard my comment above. I did some research on this and my suggestion above is of no consequence.

When you call setSupportActionBar(Toolbar), the following happens:

public void setSupportActionBar(Toolbar toolbar) {
    ....
    ToolbarActionBar tbab = new ToolbarActionBar(toolbar, ((Activity) mContext).getTitle(),
            mAppCompatWindowCallback);
    mActionBar = tbab;
    ....
}

So, subsequent calls to getSupportActionBar() return an instance of ToolbarActionBar. Take a look at how this class implements the feature we're interested in:

setShowHideAnimationEnabled(boolean): As noted by you, this method makes no difference.

@Override
public void setShowHideAnimationEnabled(boolean enabled) {
    // This space for rent; no-op.
}

show(): only makes the actionbar visible - no animation support.

@Override
public void show() {
    // TODO: Consider a better transition for this.
    // Right now use no automatic transition so that the app can supply one if desired.
    mDecorToolbar.setVisibility(View.VISIBLE);
}

hide(): only makes the actionbar visible - again, no animation support.

@Override
public void hide() {
    // TODO: Consider a better transition for this.
    // Right now use no automatic transition so that the app can supply one if desired.
    mDecorToolbar.setVisibility(View.GONE);
}

The comments in show() and hide() hint that the developer should provide the animated transition. Perhaps, something like this:

protected void hideActionBar(){
    final ActionBar ab = getSupportActionBar();
    if (ab != null && ab.isShowing()) {
        if(mToolbar != null) {
            mToolbar.animate().translationY(-112).setDuration(600L)
                    .withEndAction(new Runnable() {
                        @Override
                        public void run() {
                            ab.hide();
                        }
                    }).start();
        } else {
            ab.hide();
        }
    }
}

protected void showActionBar(){
    ActionBar ab = getSupportActionBar();
    if (ab != null && !ab.isShowing()) {
        ab.show();
        if(mToolbar != null) {
            mToolbar.animate().translationY(0).setDuration(600L).start();
        }
    }
}

The mToolbar.animate()..... part was written from memory - syntax may not be correct :(. You can also add .alpha(0(during hide) or 1(during show)) to make the transition look better.

Implementation:

What should be clear by now is that getSupportActionBar().show() & hide() don't care what you do with your Toolbar along with these method calls. Moreover, the Toolbar is to be treated as any other View inside your Activity. Keeping these points in mind, the problem boils down to - how do we animate hiding (& later, showing) of a View. Since we need the Activity content to slide with the hiding (or showing) Toolbar, I suggest the following implementation. Note that this is just a basic run-of-the-mill routine. You can surely fine tune this, or come up a totally different (read better) animated transition:

// holds the original Toolbar height.
// this can also be obtained via (an)other method(s)
int mToolbarHeight, mAnimDuration = 600/* milliseconds */;

ValueAnimator mVaActionBar;

void hideActionBar() {
    // initialize `mToolbarHeight`
    if (mToolbarHeight == 0) {
        mToolbarHeight = mToolbar.getHeight();
    }

    if (mVaActionBar != null && mVaActionBar.isRunning()) {
        // we are already animating a transition - block here
        return;
    }

    // animate `Toolbar's` height to zero.
    mVaActionBar = ValueAnimator.ofInt(mToolbarHeight , 0);
    mVaActionBar.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            // update LayoutParams
            ((AppBarLayout.LayoutParams)mToolbar.getLayoutParams()).height
                    = (Integer)animation.getAnimatedValue();
            mToolbar.requestLayout();
        }
    });

    mVaActionBar.addListener(new AnimatorListenerAdapter() {
        @Override
        public void onAnimationEnd(Animator animation) {
            super.onAnimationEnd(animation);

            if (getSupportActionBar() != null) { // sanity check
                getSupportActionBar().hide();
            }
        }
    });

    mVaActionBar.setDuration(mAnimDuration);
    mVaActionBar.start();
}

void showActionBar() {
    if (mVaActionBar != null && mVaActionBar.isRunning()) {
        // we are already animating a transition - block here
        return;
    }

    // restore `Toolbar's` height
    mVaActionBar = ValueAnimator.ofInt(0 , mToolbarHeight);
    mVaActionBar.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            // update LayoutParams
            ((AppBarLayout.LayoutParams)mToolbar.getLayoutParams()).height
                    = (Integer)animation.getAnimatedValue();
            mToolbar.requestLayout();
        }
    });

    mVaActionBar.addListener(new AnimatorListenerAdapter() {
        @Override
        public void onAnimationStart(Animator animation) {
            super.onAnimationStart(animation);

            if (getSupportActionBar() != null) { // sanity check
                getSupportActionBar().show();
            }
        }
    });

    mVaActionBar.setDuration(mAnimDuration);
    mVaActionBar.start();
}

In your comment, you mentioned I do see an animation now but the space still gets reserved for the toolbar until ab.hide() happens. To me, this implies that you are using AppBarLayout to host the Toolbar. If this is not so, let me know and we'll figure something out.

Lastly, calls to these methods will be dispatched based on:

if (getSupportActionBar().isShowing()) {
    hideActionBar();
} else {
    showActionBar();
}
Vikram
  • 51,313
  • 11
  • 93
  • 122
  • Thanks for your extensive research. I do see an animation now but the space still gets reserved for the toolbar until ab.hide() happens. This will make the content jump up after the animation instead of together with the animation. – Bart Burg Nov 26 '15 at 12:09
  • @BartBurg Thanks for the edit. I've added some more information along with sample code above. See if this can get you going with what you have in mind. – Vikram Dec 01 '15 at 05:48
10

If you hide or show with default animation try this:

Add android:animateLayoutChanges="true" in your parent toolbar In this case in AppBarLayout

<android.support.design.widget.AppBarLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:theme="@style/AppTheme.AppBarOverlay"
    android:animateLayoutChanges="true">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="?attr/colorPrimary"
        app:popupTheme="@style/AppTheme.PopupOverlay"

        />

</android.support.design.widget.AppBarLayout>

Code for toggle hide and show

final ActionBar actionBar = getSupportActionBar();

if (actionBar != null) {

    if (actionBar.isShowing()) {
        actionBar.hide();
    } else {
        actionBar.show();
    }

}
Codelaby
  • 2,604
  • 1
  • 25
  • 25
8

You can use the below code in the xml ie, for the toolbar parent for animating it when you call hide/show.

android:animateLayoutChanges="true"

OR this

Hiding

toolbarParent.animate().translationY(-toolbarHeight).setInterpolator(new AccelerateInterpolator(2)).start();

Showing

toolbarParent.animate().translationY(0).setInterpolator(new DecelerateInterpolator(2)).start();
Anoop M Maddasseri
  • 10,213
  • 3
  • 52
  • 73
0

I suggested you try cheesesquare sample. this is a layout that collapsing & expanding toolbar.

<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/main_content"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/appbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
            app:layout_scrollFlags="scroll|enterAlways|snap" />

        <android.support.design.widget.TabLayout
            android:id="@+id/tabs"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

    </android.support.design.widget.AppBarLayout>

    <android.support.v4.view.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="end|bottom"
        android:layout_margin="@dimen/fab_margin"
        android:src="@drawable/ic_done" />

</android.support.design.widget.CoordinatorLayout>
Mohammad Hossein Gerami
  • 1,360
  • 1
  • 10
  • 26
0

If you are using a CoordinatorLayout in your activity, use this:

<android.support.v7.widget.Toolbar
    android:id="@+id/toolbar"
    android:layout_width="match_parent"
    android:layout_height="?attr/actionBarSize"
    android:background="?attr/colorPrimary"
    app:layout_scrollFlags="scroll|enterAlways" />

The app:layout_scrollFlags="scroll|enterAlways" line will cause our Toolbar to scroll off the screen when the user scrolls down the list and as soon as he starts scrolling up the Toolbar will show up again.

Jaydev
  • 1,794
  • 20
  • 37