54

I'm using the new toolbar widget introduced in the appcompat / support-v7. I would like to hide/show the toolbar depending on if the user is scrolling up/down the page, just like in the new Google's playstore app or NewsStand app. Is there something built into the toolbar widget for this or should I be using it in conjunction with FrameLayout and ObservableScrollView?

nomongo
  • 3,435
  • 7
  • 30
  • 33

12 Answers12

80

As far as I know there is nothing build in that does this for you. However you could have a look at the Google IO sourcecode, especially the BaseActivity. Search for "auto hide" or look at onMainContentScrolled

In order to hide the Toolbar your can just do something like this:

toolbar.animate().translationY(-toolbar.getBottom()).setInterpolator(new AccelerateInterpolator()).start();

If you want to show it again you call:

toolbar.animate().translationY(0).setInterpolator(new DecelerateInterpolator()).start();
Kuno
  • 3,492
  • 2
  • 28
  • 44
  • 1
    In onCreate your toolbar is not layed out yet. That's why getBottom returns 0 so there is no distance to animate. Add an OnGlobalLayoutListener to your toolbars ViewTreeObserver and start the animation in the callback. Don't forget to remove the OnGlobalLayoutListener afterwards. – Kuno Nov 17 '14 at 10:54
  • I am not familiar with OnGlobalLayoutListener. Can u give me some code ? – AruLNadhaN Nov 17 '14 at 16:41
  • I tried it.The toolbar is not hiding.It changes its color to the background color.While scrolling it looks weird! – AruLNadhaN Nov 19 '14 at 01:51
  • works, but requires API 16, any way we can make this work on API 9? – SavageKing Dec 04 '14 at 14:19
  • 1
    If i am not mistaken, it requires API 12. For compatibility with lower API levels, use http://nineoldandroids.com/ – Kuno Dec 04 '14 at 14:24
  • Thanks for the quick reply but i don't know why it is not working perfectly. Following is my code. Actually sometimes i have to click multiple times to hide/show the toolbar. `@Override public boolean dispatchTouchEvent(MotionEvent ev) { if (mIsShowing) { hideToolBar(); mIsShowing = false; } else { showToolBar(); mIsShowing = true; } return super.dispatchTouchEvent(ev); } private void hideToolBar() { mToolBar.animate().translationY(-mToolBar.getBottom()) .setInterpolator(new AccelerateInterpolator()).start(); } ` – Shajeel Afzal Mar 16 '15 at 12:19
  • and to show the animation: `private void showToolBar() { mToolBar.animate().translationY(0) .setInterpolator(new DecelerateInterpolator()).start(); } ` – Shajeel Afzal Mar 16 '15 at 12:20
  • When do you want the toolbar to hide/show? Almost certainly dispatchTouchEvent is not the right place for this. – Kuno Mar 16 '15 at 13:00
  • @Kuno This takes care of animating the toolbar, but the views below it do not animate as well to fill in the space. I would think that the layout_below property of my RelativeLayout would be preserved, but this is not the case. Any idea how to handle this? – Mike Ortiz May 10 '16 at 03:30
  • Interesting solution but it is not working, the CONTENT inside the toolbar is animated but the VIEW itself is still in position. – Lampione Dec 11 '16 at 12:01
42

For hiding the toolbar you can just do :

getSupportActionBar().hide();

So you just have to had a scroll listener and hide the toolbar when the user scroll !

Philippe
  • 1,567
  • 16
  • 18
  • Good solution, still not providing an animation though. That's strange because other Material Design fundamental views (as FAB) provide an animation when showing/hiding – Lampione Dec 11 '16 at 12:03
27

Hide:

getSupportActionBar().hide();

Show:

getSupportActionBar().show();
Andrew
  • 36,676
  • 11
  • 141
  • 113
16

The answer is straightforward. Just implement OnScrollListenerand hide/show your toolbar in the listener. For example, if you have listview/recyclerview/gridview, then follow the example.

In your MainActivity Oncreate method, initialize the toolbar.

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        toolbar = (Toolbar) findViewById(R.id.toolbar);
        if (toolbar != null) {
            setSupportActionBar(toolbar);
            getSupportActionBar().setDisplayShowHomeEnabled(true);
        }
}

And then implement the OnScrollListener

public RecyclerView.OnScrollListener onScrollListener = new RecyclerView.OnScrollListener() {
        boolean hideToolBar = false;
        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
            super.onScrollStateChanged(recyclerView, newState);
            if (hideToolBar) {
                ((ActionBarActivity)getActivity()).getSupportActionBar().hide();
            } else {
                ((ActionBarActivity)getActivity()).getSupportActionBar().show();
            }
        }

        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            super.onScrolled(recyclerView, dx, dy);
            if (dy > 20) {
                hideToolBar = true;

            } else if (dy < -5) {
                hideToolBar = false;
            }
        }
    };

I got the idea from: https://stackoverflow.com/a/27063901/1079773

Community
  • 1
  • 1
Abdul Rahman
  • 1,833
  • 1
  • 21
  • 21
8

Android Design Support Library can be used to show/hide toolbar.

See this. http://android-developers.blogspot.kr/2015/05/android-design-support-library.html

And there are detail samples here. http://inthecheesefactory.com/blog/android-design-support-library-codelab/en

hoi
  • 2,168
  • 20
  • 22
2

There are actually quite a number of ways to hide/show the toolbar while you are scrolling the content. One of the ways is to do it via the Android Design Support Library or more specifically the Coordinator layout aka. super-powered frame layout.

Basically all you need to do is to have the following structure in your layout file and you should be able to achieve the result that you want.

<CoordinatorLayout>
   <AppBarLayout>
   </AppBarLayout>
   <NestedScrollView>
   </NestedScrollView>
</CoordinatorLayout>

I have actually made a video to explain how it can be done in a step by step manner. Feel free to check it out and let me know if it helps. Thanks! :)

https://youtu.be/mEGEVeZK7Nw

Jack Tiong
  • 937
  • 8
  • 12
2

Just add this property inside your toolbar and its done

app:layout_scrollFlags="scroll|enterAlways"

Isn't is awesome

pacholik
  • 8,607
  • 9
  • 43
  • 55
Rishab Surana
  • 1,977
  • 1
  • 11
  • 20
1

I've been trying to implement the same behavior, here is the brunt of code showing and hiding the toolbar (put in whatever class containing your RecyclerView):

int toolbarMarginOffset = 0

private int dp(int inPixels){
    return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, inPixels, getApplicationContext().getResources().getDisplayMetrics());
}

public RecyclerView.OnScrollListener onScrollListenerToolbarHide = new RecyclerView.OnScrollListener() {
    @Override
    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
        super.onScrolled(recyclerView, dx, dy);
        toolbarMarginOffset += dy;
        if(toolbarMarginOffset>dp(48)){
            toolbarMarginOffset = dp(48);
        }
        if(toolbarMarginOffset<0){
            toolbarMarginOffset = 0;
        }
        ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams)toolbar.getLayoutParams();
        params.topMargin = -1*toolbarMarginOffset; 
        toolbar.setLayoutParams(params);
    }
};

I've included the dp function to convert from pixels to dp but obviously set it to whatever your toolbar height is. (replace dp(48) with your toolbar height)

Where-ever you setup your RecyclerView include this:

yourListView.setOnScrollListener(onScrollListenerToolbarHide);

However, there are a couple additional issues if you are also using a SwipeRefreshLayout.

I've had to set the marginTop of the first element in the adapter for the RecyclerView to the Toolbar's height plus original offset. (A bit of a hack I know). The reason for this is I found that if I changed my above code to include changing the marginTop of the recyclerView while scrolling it was a jittery experience. So that's how I overcame it. So basically setup your layout so that your toolbar is floating on top of the RecyclerView (clipping it) Something like this (in onBindViewHolder of your custom RecyclerView adapter) :

 if(position==0){
     ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams)holder.card.getLayoutParams();
     // params.height = ViewGroup.LayoutParams.WRAP_CONTENT;
     params.topMargin = dp(10+48);
 }

And lastly, since there is a large offset the RecyclerViews refresh circle will be clipped, so you'll need to offset it (back in onCreate of your class holding your RecyclerView):

swipeLayout.setProgressViewOffset(true,dp(48),dp(96));

I hope this helps someone. Its my first detailed answer so I hope I was detailed enough.

Timwillhack
  • 81
  • 2
  • 3
1

To hide the menu for a particular fragment:

 setHasOptionsMenu(true); //Inside of onCreate in FRAGMENT:  


   @Override
   public void onPrepareOptionsMenu(Menu menu) {
       menu.findItem(R.id.action_search).setVisible(false);
   }
Parama Sudha
  • 2,583
  • 3
  • 29
  • 48
0

I implemented a utility class to do the whole hide/show Toolbar animation when scrolling. You can see the article here http://rylexr.tinbytes.com/2015/04/27/how-to-hideshow-android-toolbar-when-scrolling-google-play-musics-behavior/. Source code is here https://github.com/rylexr/android-show-hide-toolbar.

rylexr
  • 2,106
  • 2
  • 19
  • 21
0

A library and demo with the complete source code for scrolling toolbars or any type of header can be downloaded here:

https://github.com/JohannBlake/JBHeaderScroll

Headers can be Toolbars, LinearLayouts, RelativeLayouts, or whatever type of view you use to create a header.

The scrollable area can be any type of scroll content including ListView, ScrollView, WebView, RecyclerView, RelativeLayout, LinearLayout or whatever you want.

There's even support for nested headers.

It is indeed a complex undertaking to synchronize headers (toolbars) and scrollable content the way it's done in Google Newsstand.

This library doesn't require implementing any kind of onScrollListener.

The solutions listed above by others are only half baked solutions that don't take into consideration that the top edge of the scrollable content area beneath the toolbar has to initially be aligned to the bottom edge of the toolbar and then during scrolling the content area needs to be repositioned and possibly resized. The JBHeaderScroll handles all these issues.

Johann
  • 27,536
  • 39
  • 165
  • 279
0

There is an Android library called Android Design Support Library that's a handy library where you can find of all of those Material fancy design things that the Material documentation presents without telling you how to do them.

It's well presented in this Android Blog post. The "Collapsing Toolbar" in particular is what you're looking for.

CristinaTheDev
  • 1,952
  • 2
  • 17
  • 25