Parallax Scrolling Tabs with Android Design Support Library

Material Design has seen the rise in on-scroll animations in Android apps. Previously we’ve seen such examples with the Flexible Space with Image and Quick Return pattern. In this post, we’ll look at making parallax scrolling Tabs using Android Design Support Library.

Parallax scrolling has been very popular in web design and now in app development as well. I’ve seen quite a few people wanting to implement this and I wanted to provide a solution without using a third party library. So here it is.

This is nothing but the Flexible Space with Image pattern with an added TabLayout.

parallax scroll header tabs

New to Android Design Support Library? Read these:

Parallax Scrolling Layout

Unlike the typical Material Design Tabs attached to the Toolbar, Tabs here are transparent. Here is the layout.

<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/htab_maincontent"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true">

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

        <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/htab_collapse_toolbar"
            android:layout_width="match_parent"
            android:layout_height="256dp"
            android:fitsSystemWindows="true"
            app:contentScrim="?attr/colorPrimary"
            app:layout_scrollFlags="scroll|exitUntilCollapsed">

            <ImageView
                android:id="@+id/htab_header"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@drawable/header"
                android:fitsSystemWindows="true"
                android:scaleType="centerCrop"
                app:layout_collapseMode="parallax" />

            <android.support.v7.widget.Toolbar
                android:id="@+id/htab_toolbar"
                android:layout_width="match_parent"
                android:layout_height="104dp"
                android:gravity="top"
                android:minHeight="?attr/actionBarSize"
                app:layout_collapseMode="pin"
                app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
                app:titleMarginTop="13dp" />

            <android.support.design.widget.TabLayout
                android:id="@+id/htab_tabs"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                android:layout_gravity="bottom"
                app:tabIndicatorColor="@android:color/white" />

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

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

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

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

If you’ve taken my word of advice and gone through my posts linked above, you would note that I have simply added a TabLayout wrapped in a CollapsingToolbarLayout.

This positioning is important to get the parallax scrolling to work.

Layout Breakdown

Note the highlighted lines:

18. CollapsingToolbarLayout’s height denotes the height we want our header view to have

35. Toolbar height = (Toolbar Height) 56dp + (Tabs Height) 48dp = 104dp

36. & 40. To vertically adjust and center Toolbar title.

layout-parallax-scrolling-breakdown

NOTE:

Altering the Toolbar height causes its title to get misaligned. This is why I’ve opted for a manually positioning the title. More on this at StackOverflow.

Setting up ViewPager in Activity.java

In case you forgot, the Tabs need a ViewPager to work with, so let’s take care of that in our Activity.java.

public static class DummyFragment extends Fragment {
     
      public DummyFragment() {
      }

      @Override
      public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
          View view = inflater.inflate(R.layout.dummy_fragment, container, false);
          ...
          RecyclerView recyclerView = (RecyclerView) view.findViewById(R.id.dummyfrag_scrollableview);

          LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity().getBaseContext());
          recyclerView.setLayoutManager(linearLayoutManager);

          SimpleRecyclerAdapter adapter = new SimpleRecyclerAdapter(list);
          recyclerView.setAdapter(adapter);
          ...
          return view;
      }
  }

Note that DummyFragment is just a placeholder which I’m using with a different background color for each of my Tabs. You on the other hand must define a Fragment accordingly for each of your Tabs.

ViewPager Adapter

A minimal Adapter for our ViewPager. (To hold 3 Fragments)

static class ViewPagerAdapter extends FragmentPagerAdapter {
        private final List<Fragment> mmFragmentTitleList FragmentList = new ArrayList<>();
        private final List<String> = new ArrayList<>();

        public ViewPagerAdapter(FragmentManager manager) {
            super(manager);
        }

        @Override
        public Fragment getItem(int position) {
            return mFragmentList.get(position);
        }

        @Override
        public int getCount() {
            return mFragmentList.size();
        }

        public void addFrag(Fragment fragment, String title) {
            mFragmentList.add(fragment);
            mFragmentTitleList.add(title);
        }

        @Override
        public CharSequence getPageTitle(int position) {
            return mFragmentTitleList.get(position);
        }
    }

Hooking up ViewPager with TabLayout

Finally we’ll attach the ViewPager to our TabLayout in the Activity’s onCreate() method.

... 
TabLayout tabLayout = (TabLayout) findViewById(R.id.htab_tabs);
        tabLayout.setupWithViewPager(viewPager);

 tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
            @Override
            public void onTabSelected(TabLayout.Tab tab) {

                viewPager.setCurrentItem(tab.getPosition());

                switch (tab.getPosition()) {
                    case 0:
                        showToast("One");
                        break;
                    case 1:
                        showToast("Two");
                        ...
                  }
               }

  private void setupViewPager(ViewPager viewPager) {
        ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
        adapter.addFrag(new DummyFragment(getResources().getColor(R.color.accent_material_light)), "CAT");
        adapter.addFrag(new DummyFragment(getResources().getColor(R.color.ripple_material_light)), "DOG");
        adapter.addFrag(new DummyFragment(getResources().getColor(R.color.button_material_dark)), "MOUSE");
        viewPager.setAdapter(adapter);
    }
...

The setupViewPager() method simply initializes my Fragment and adds them to the ViewPager.

Nothing out of the ordinary here. The Material Design Tabs post does the same thing, which is why this has minimal explanation. However if you get stuck anywhere, below is a link to the source code (GitHub) which you can refer to 🙂

Dynamic Tab color with Palette API

The color you see the Toolbar + TabLayout take, is picked from the header image. Courtesy of the Palette API.

Using this, we’ll set colors for the Toolbar, TabLayout and Status Bar. This is easily done by the following code snippet:

Palette.from(bitmap).generate(new Palette.PaletteAsyncListener() {
            @SuppressWarnings("ResourceType")
            @Override
            public void onGenerated(Palette palette) {

                int vibrantColor = palette.getVibrantColor(R.color.primary_500);
                int vibrantDarkColor = palette.getDarkVibrantColor(R.color.primary_700);
                collapsingToolbarLayout.setContentScrimColor(vibrantColor);
                collapsingToolbarLayout.setStatusBarScrimColor(vibrantDarkColor);
            }
        });

Final Output

With everything in place, run your app and scroll down and watch that beautiful parallax scrolling.

parallax scrolling header tab op

We have a neat TabLayout that plays nice with our Toolbar. Our header image scrolls nicely and fades into our image’s primary vibrant color.

As you can see this is a neat pattern in use which many of you would have seen. A perfect use case for this would be in apps that have categories (sub divisions) like the Play Store app, and also require a neat header image (Master Detail being the perfect example).


Find the source code for this project on GitHub.

Alternate Library

If you’re not satisfied with the parallax scrolling the Design Support Library provides, or desire a greater degree of control and flexibility, you can use MaterialViewPager by florent37 on GitHub.

Do share the post if you liked it!

Cheers.

Suleiman

Android developer and tech enthusiast. Love creating apps with good UI UX design. I also like to sketch and listen to Chillstep.

You may also like...

  • Pingback: Parallax Scrolling Tabs with Android Design Support Library | Android Bookmarks()

  • Please update to the latest support libraries versions first.

    • Vaibhav Desai

      Hey, issue is fixed…. Thanks 🙂

  • Mathieu M

    Great tuto, thanks a lot!

  • Saiteja Parsi

    I followed the same, but in collapse position, (I think) the toolbar overlaps with tab layout. The positioning seems good but when I touch any tab the does not respond. Please let me know where I can go wrong

    • Hi Saiteja,
      Thanks for that useful gist for your code. Since you’re using a DrawerLayout, why don’t you inflate your Coordinator layout part from a Fragment? Makes it more clean and easier to isolate the error.

      Plus I’m not sure you need the marginTop attribute for your Tabs. Also try addding android:clickable=”true”

      • Saiteja Parsi

        My problem was solved. I mistakenly gave 4dp elevation to toolbar, which stays above tablayout when collapsed. So tabs are not clickable. I removed it and it works fine. Thanks for good tutorial. It is very helpful

        • That’s good to hear Saiteja. Happy to know you were able to resolve the issue. If you really liked the tutorial, do consider sharing so others find this blog too.

  • Akshay Chordiya

    Thank you for this article. But it’s not working I copied the same XML layout.
    BTW I’m using Support Library v23.1.1.
    I hope you reply me soon.

    • Hi Akshay,
      I suggest you go through it once again. I’ve updated my libraries to 23.1.1 as well and experience no such issues. Still works like a charm.
      Alternatively, you could consider seeing my GitHub sample project.

  • Acp Vinay Kumar

    i followed your code and implemented this but am facing two issues
    1)my header image is not fitting/overlapping status bar
    2)Tittle problem am not getting tittle on toolbar
    please solve

    • Please refer to my GitHub code sample linked below.
      You can set a title simply by using :
      getSupportActionBar().setDisplayShowTitleEnabled(true);
      getSupportActionBar().setTitle(“title”);

      • Acp Vinay Kumar

        that’s fine but header image is not overlapping my status bar it’s showing default primarkdarkcolor how to overlap that wid header image plz solve’

        • Did you go through my code sample first? If you did, you shouldn’t be facing this issue.

          • Acp Vinay Kumar

            Thank you problem solved

  • Acp Vinay Kumar

    how to implement onListclicklistner in the dummy fragment
    please help

  • harsha

    is it possibl e to show tabs dynamically based on the selected list item from another view.

  • Danil Kolesnikov

    Hi,
    Is it possible to change the header image once the user slides between tabs?
    (Each tab has its own header image)

    • Hi Danil,
      Yes, you could do that via your code.
      Create a tab listener and change the image depending upon which tab is selected.

  • wargh

    In your github project, under the TabsHeaderActivity, you have a collapsing toolbar with tabs. If I enable the expanded title and try to collapse it, the title is out of place. I’ve tried a few things to fix it but didn’t succeed. Do you know how to fix this? See attached screenshots

    • Hi there,
      By default, without me trying to manually adjust the title position, the previous versions of the Support Library wouldn’t fit it correctly.
      Do remove the positioning attributes and give it a shot, I’ve tested it to be working fine.

      • wargh

        Am using 23.1.1 of the support libraries.

        compile ‘com.android.support:design:23.1.1’

        I got rid of the title positioning attribute app:titleMarginTop=”13dp” but title is still positioned below where it should be. Left the toolbar height at “104dp”

        Can you update your github proj with the changes so I can take a look?

        Thank you

        • I just updated to v23.2.0 of the Support library. Haven’t changed anything in my code. Still works like a charm. I’d suggest you go through my GitHub repository and see if you’re doing anything different.

          • wargh

            I pulled directly from your GitHub source and only changed 1 line in TabsHeaderActivity.java. From

            collapsingToolbarLayout.setTitleEnabled(false);

            to

            collapsingToolbarLayout.setTitleEnabled(true);

            I also updated to v23.2.0 but it didn’t help. I also tested on Android 4.4, 5.1, and 6.0. No luck unfortunately.

          • Like I said, I’ve got the alignment straight after a lot of trial and error. I can confirm that my source code even works with the latest support libraries. I’ve personally tested this for you. So if you’re going to modify the layout, it would obviously break.

          • wargh

            I can’t quite figure it out. I didn’t change any of your layout. Just one source code change shown above to allow the collapsing toolbar to display the title. I would think the Google Support Libraries should be able to handle it. Perhaps someone else can try it and see what happens. Anyway, won’t bother you anymore. Thanks for the tutorials, they are really helpful.

  • HakoHec_3aperaLc9

    @suleiman19:disqus Hi!
    Is this possible add buttons to Header Tab?

    • Hi,
      You can add it to the Toolbar, but not to the TabLayout.

  • Navneet Sharma

    hii,i followed your tutorial and stuck at one point..i.e in my first fragment i add a scrollbar and it dosent scroll upwards when i scroll from viewpager..but i works when scroll with tabs.

    • Jay B

      I have a similar issue using scrollview

      • Hi Jay,
        Please use either a NestedScrollView or a RecyclerView.

  • Jay B

    I’m having an issue with the title placement. The title is overlapping the tabs and it’s moving with the collapse motion. When collapsing, it settles in a final resting position of about 2 inches below the back button and still overlaps the tabs 🙁 I’m using support library v7 23.2.0. I’ve also tried defining a custom layout for the toolbar as a linear layout with a textview inside with gravity set to top, but the same thing happens.

    • Have you taken a look at my GitHub source? I’ve adjusted the title’s position accordingly in the XML layout.

      • Jay B

        I cross checked it with your XML and adding the following lines fixed it:

        // Disable collapsing toolbar title (fixes positioning)
        final CollapsingToolbarLayout collapsingToolbarLayout = (CollapsingToolbarLayout) findViewById(R.id.htab_collapse_toolbar);
        collapsingToolbarLayout.setTitleEnabled(false);

        However, I’m using a scrollview with linear layout instead of a recyclerview and when I scroll in the scrollview, the toolbar does not collapse, how can I link these two actions?

        • You must use either a NestedScrollView or a RecyclerView for it to work.

  • Did you cross check with the Activity’s XML Layout as well?

    • wargh

      I left the activity’s XML layout the same as your original source – didn’t make any changes to it. Only changed the above mentioned source line.

      • Personally, I wasn’t able to get the collapsing title to play nice with this animation. So I simply set a title to the Toolbar instead.

        • wargh

          Yeah, bizarre. Probably a bug in the support library.

  • curio

    Same here, vanilla checkout of the repo (a38bd433c13e93a77dec436cb9b6e6744cd6958c), just this one change to get a parallax title — text overlaps with tabs when expanded, sits below toolbar when collapsed.

  • curio

    Yep, same here, still today, latest checkout and just that one change. Except in the last screenshot (expanded layout), the title even touches the tab labels.

    • Setting the Collapsing Toolbar title to false is what enables me to do this animation. You can alternatively set the Toolbar’s title instead.

  • Great tutorial. How to add Search in Toolbar using SearchView?

  • Данияр Жадырасын

    May I look at source code? Share the link please:)

    • It’s available at the post’s end.

  • Nikita Soloman

    could you please send me GitHub sample project

    url

  • Rana Saqib Manj

    Hi ! nice tutorial but I have a question.I want to make an app like whatsapp. As you know In whatsapp when we open profile any person then collapsing toolbar layout is open by default height and after we expand this and see full pic.Similarly I want to done this in our app.So plz help me …. thanks in Advance

  • Gon Her

    Hi. as is done to launch a second fragment adapter?

  • Jeremy

    Great tutorial!
    But I’m experiencing a problem 🙁
    I started my project using the navigation drawer template and I’m trying to implement the parallax tabs on my first fragment which would be “Home”. However I want to keep the main app toolbar for the other fragments and only show the parallax tabs in my home fragment. How can I accomplish this? Thanks in advance

    • Hi Jeremy,
      This is how I would do it:
      Let the Toolbar + Tabs remain in the Activity. So all fragments would have it.
      But let the Tabs remain visible ONLY for the 1st fragment.
      You will also have to programmatically fix the collapsible property for the other Fragments.
      Good luck.