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