Material Design Tabs with Android Design Support Library

This is my third post where I continue to bring you more from the Design Support Library. Let’s look at adding a Material Design Tab strip for our apps with on scroll animations.

Tabs make it easy to explore and switch between different views. Provides a way for displaying grouped content.

– Material Design, Tab Component

This article has been updated for AndroidX!

Material Design Tabs made easy

You can see Material Design tabs popularly on the Play Store app, and more recently on WhatsApp as well (after their Material Design update).

material design tabs in play store app
Material Design Tabs in Play Store
Tabs in WhatsApp

To implement Tabs earlier, we had to rely on external libraries. Also, let’s not forget the hide on scroll animations which we had to make ourselves!

When you’re done reading this post, you’ll be able to create amazing Material Design tabs for your apps. Like the ones above.

So let’s get to it!

Also read:


Layout

Have you closely observed how Tabs actually behave?

When you click a Tab, it becomes active and slides in a new screen. Rather a new sub-screen called Fragment. We either tap a Tab, or swipe left or right to access adjacent Tabs.

Tabs are typically found anchored to the bottom of the Toolbar.

In essence, the entirety of those Tab screens are Fragments, which will be handled by a ViewPager. Think of it like a gallery slideshow.

But before we dive into all of that, let’s setup our main layout.

Here’s a skeleton of the layout.

<androidx.coordinatorlayout.widget.CoordinatorLayout>
   <com.google.android.material.appbar.AppBarLayout>
      <androidx.appcompat.widget.Toolbar />
      <!-- The Tab rests directly below the Toolbar, attached below it -->
      <com.google.android.material.tabs.TabLayout />
   </com.google.android.material.appbar.AppBarLayout>
   <!-- Helps handing the Fragments to load for each Tab -->
   <android.support.v4.view.ViewPager />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

For creating Tabs, we use the TabLayout widget class. This is a new widget, part of the Design Support Library.

Additionally, you might notice other new widgets as well. If you’re not familiar with them, I strongly suggest you go through this post first.

That’s the skeleton of our Activity layout. Let’s start defining it now. Open your Activity’s layout.xml

<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.google.android.material.appbar.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

        <androidx.appcompat.widget.Toolbar
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:layout_scrollFlags="scroll|enterAlways"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />

        <com.google.android.material.tabs.TabLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </com.google.android.material.appbar.AppBarLayout>

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

</androidx.coordinatorlayout.widget.CoordinatorLayout>

The scroll flags for the Toolbar specify how it must behave upon scroll (i.e. its animation).

scroll|enterAlways says make my Toolbar react to scroll events. Hide it when scrolling down, and reveal it when scrolling back up.

This behavior will be indicated by our ViewPager which will be hold our Fragments. The Fragments hold our scrollable view. So when we scroll down a list, the Toolbar knows when to react.

Tabs attached below Toolbar
TabLayout and Toolbar in XML preview

Setting up TabLayout

That’s our main layout. Now open up YourActivity.java.

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

final ViewPager viewPager = findViewById(R.id.tabanim_viewpager);
setupViewPager(viewPager);

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

First, start off by setting up your Toolbar. Then define the ViewPager. We’ll attach an Adapter to in the setupViewPager() method. Finally define the TabLayout, and attach the ViewPager to it.

Remember that we must attach an adapter to the ViewPager first. Then attach the ViewPager to TabLayout.

setupViewPager() method

Here I will simply initialize a ViewPagerAdapter (our custom adapter class which I will explain in a moment) and add 3 fragments to it.

For simplicity’s sake, I will be attached the same Fragment thrice which different backgrounds. However in a real app scenario, you would be attaching different once.

Let’s assume you have 3 tabs. Games, Movies, Books. Then you should be loading their respective fragments here in ORDER of the tabs.

private void setupViewPager(ViewPager viewPager) {
 ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager(), FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
 adapter.addFrag(new DummyFragment(
  ContextCompat.getColor(this, R.color.blue_grey)), "CAT");
 adapter.addFrag(new DummyFragment(
  ContextCompat.getColor(this, R.color.amber)), "DOG");
 adapter.addFrag(new DummyFragment(
  ContextCompat.getColor(this, R.color.cyan)), "MOUSE");
 viewPager.setAdapter(adapter);
}

So let’s define our Tabs and give each one a name. Cat, Dog and Mouse (for the lack of better names) will be my 3 Tabs.

Defining our Adapter

Remember that ViewPagerAdapter I told you about? Let’s create a class for it now, extend FragmentPagerAdapter and implement the required methods.

We need to store, first our Fragments itself, and then the Tab titles. We’ll do this with a List.

private final List<Fragment> mFragmentList = new ArrayList<>();
private final List<String> mFragmentTitleList = new ArrayList<>();

Our entire Adapter class will look like this:

class ViewPagerAdapter extends FragmentPagerAdapter {
 private final List < Fragment > mFragmentList = new ArrayList < > ();
 private final List < String > mFragmentTitleList = 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);
 }
}

Note that addFrag() is my own custom method. I’m using it to add Fragments and its titles to the ViewPager adapter.

tabs-defined
Tabs with ViewPager Adapter

Tab Fragment

Now that we’ve done all this, you might be wondering what is ‘DummyFragment‘ and why its showing an error?

DummyFragment is to be your Fragment (obvious from the name), which holds the layout content. This is what we see when we swipe to each Tab. Ideally, you should be loading a different Fragment for each tab.

The layout could be anything. But I don’t want to complicate things.

Just be sure for testing, to make a list long enough so that its scrollable. This will allow the Quick Return scroll animation to work.

I encourage you to create your own layouts for the Tab Fragment. You could refer mine, but if you’re like “Hey, I can do this!“, then good job! Scroll down to the next section.

    public static class DummyFragment extends Fragment {
        int color;
        SimpleRecyclerAdapter adapter;

        public DummyFragment() {
        }

        @SuppressLint("ValidFragment")
        public DummyFragment(int color) {
            this.color = color;
        }

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

            final FrameLayout frameLayout = view.findViewById(R.id.dummyfrag_bg);
            frameLayout.setBackgroundColor(color);

            RecyclerView recyclerView = view.findViewById(R.id.dummyfrag_scrollableview);

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

            List<String> list = Arrays.asList(VersionModel.data);

            adapter = new SimpleRecyclerAdapter(list);
            recyclerView.setAdapter(adapter);

            return view;
        }
    }
tabs with list
Tabs with Fragments attached
Tab Listener

We can interact with the TabLayout and dictate what must happen when selecting a Tab, unselecting, reselecting and so forth.

While we’re staying on topic, let me show you how we can add such a listener to it.

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");
    break;
   case 2:
    showToast("Three");
    break;
  }
 }

 @Override
 public void onTabUnselected(TabLayout.Tab tab) {}

 @Override
 public void onTabReselected(TabLayout.Tab tab) {}
});

Note viewPager.setCurrentItem(tab.getPosition()) handles changing the Fragment based on Tab click.

Yes, all it takes is to use setOnTabSelectedListener with TabLayout.OnTabSelectedListener().

Just for demonstration, I’ll show a simple Toast when you tap a Tab item. This works not only when tapping, but also when swiping left or right! In essence, a Toast pops each time the Fragment loads into view.

v23.0.0 Tab Listener Fix:

With the release of Android Marshmallow, libraries got updated to 23.0.0 including the Design Support Library. This update somehow broke the tab listener in a viewpager + tab combination. So if click listener for the tabs stops working for you, here is a suggested workaround for it, suggested by Chris Banes himself.


Material Design Tabs in Action

Let’s take a breath and break down what we’ve accomplished so far:

  1. Created our main TabLayout
  1. Initialized a ViewPager and attached an Adapter (ViewPagerAdapter) to it
  1. Attached the ViewPager to our Tabs
  2. Created the Fragment content to supply our ViewPager with

Finally with all that code behind us, lets run our app and see how it looks like.

That’s it! We’ve got some great looking Material Design Tabs (without a third party library). Created the needed adapter and even got those snazzy on scroll animations for our Toolbar.

Note the Tab underline highlight takes colorAccent by default. Also, did you just notice we got those animations to work just by defining it in XML? No Java. Cheers!

Thats what Android Design Support library allows us to do. Making the easy stuff easier.

How are you using TabLayout in your apps? Have anything else to add? Let me know in the comments.

Suleiman

Product Designer who occasionally writes code.

You may also like...

124 Responses

  1. Jalal Atsakzai says:

    Hi,

    Though I used a different approached on the tabs and fragments, I was wondering how i could set the list items more rounder corners like yours.

    • Suleiman19 says:

      Hi Jalal,
      The list items are simply using CardView 🙂
      Use the “card_view:cardCornerRadius” attribute in its XML and you’re good to go. Alternatively, you can check the code sample (end of post) for reference.

  2. Antonis Freris says:

    Hello, Thanks for the great tutorial. So i build this App that gets “text” from my uni and i parse it.
    Each semester has different Lesson names,grades ,etc, can i achieve it with this tutorial?
    I get stuck at DummyFragment that displays in every tab the same Lessons
    Any ideas on how to get fragment/adapter to show different lessons for each semester?
    Thanks in advance!

    • Suleiman19 says:

      Use the fragment’s setArguments() method to pass different “text” to each Fragment. Then based on that you can load your lessons accordingly.
      Hope that answered your question Antonis, and I’m glad the tutorial helped you.

  3. Acea Alex says:

    Hey, I made a TabLayout like this one with 2 tabs containing fragments with recyclerviews. Thing is my recyclerview items contain checkboxes. In each fragment I have a method that knows which items are selected.
    I want to have a button in the Parent Activity and call the fragment methods from it. Thing is when I do that it always returns null. Can you help me with that? Thanks a lot!

    • Suleiman19 says:

      Hi Alex,
      You can fetch the Fragment in your Activity like this (assuming you have a ViewPager setup):
      YourFragment fragment = (YourFragment) pagerAdapter.getRegisteredFragment(position);
      fragment.yourMethod();

      Of course, the success of the call depends on whether your Fragment is active, so you’ll have to check for that before making a call.
      Hope that answered your question.

  4. binoy balu says:

    Hey There. I’m not able to click cards inside of the viewpager which is implemented by recyclerview. I think something is overlapping with the same. Can you help me implement a Coordinatorlayout>Appbar>Toolbar>Tablayout>Viewpager and inside viewpager i have to click

  5. Jai says:

    Does anyone know how Google App Runtime change of AppBarLayout color ?

    http://stackoverflow.com/questions/36393840/runtime-change-of-appbarlayout-color

  6. Thalles Santos says:

    How do I change the title of the tab by an icon, like the Instagram tabs?

  7. Joel Akoupo says:

    hi Suleiman19 ,

    when i compile your code,my IDE show :

    Error:(19, 5) error: cannot find symbol class SimpleRecyclerAdapter
    Error:(28, 46) error: cannot find symbol variable dummy_fragment
    Error:(29, 77) error: cannot find symbol variable dummyfrag_bg
    Error:(31, 9) error: cannot find symbol class RecyclerView
    Error:(31, 38) error: cannot find symbol class RecyclerView
    Error:(31, 74) error: cannot find symbol variable dummyfrag_scrollableview.

    i use as library :

    compile fileTree(dir: ‘libs’, include: [‘*.jar’])
    compile ‘com.android.support:appcompat-v7:22.2.0’
    compile (‘com.android.support:design:22.2.0’){

    }
    compile ‘com.android.support:appcompat-v7:22.2.0’
    compile ‘com.android.support:palette-v7:22.2.0’
    compile(‘com.android.support:recyclerview-v7:22.0.0’) {
    }
    compile ‘com.android.support:cardview-v7:22.0.0’

    thank yu

  8. This doesn’t works into Fragment instead of Activity

    • Suleiman19 says:

      If you want it to work with Fragments, a simple idea is to add the TabLayout to your parent Activity. Then just do .setVisible(View.VISIBLE) for the Fragments that need Tabs, and View.GONE for those which don’t.

  9. Gurappa Ch says:

    Hi Suleiman,

    It works fine for me too as it is supposed to. But one issue is that the tabs does not move and become visible automatically. Say I have 5 tabs. 3 are visible and 4th one is half visible. When I select 4th tab, it does not come to visible. Same when i swipe. When I swipe to 5th page (of viewPager), 5th tab is still off the screen and not visible.
    How to make the tab layout keep scrolling automatically when swiping the view pager to right or left so that tab layout shows the currently selected tab in middle always. And rest of the tabe on it’s left or right ?
    Thanks again for the help with the article.

    • Gurappa Ch says:

      I tried with GRAVITY_FILL but of no use.

      • Gurappa Ch says:

        I could find solution for this. I had to do tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE) or app:tabMode=”scrollable” in XML.

      • Suleiman19 says:

        Hi Gurappa,

        That is precisely the solution. Brilliant!
        Good to see you kept trying and found the solution on your own. Sign of a good developer 😉
        Cheers.

      • Gurappa Ch says:

        Thanks!
        Thanks for the article again. 🙂
        Of course, I will share it with friends 🙂

  10. Gundeep Singh says:

    I followed your tutorial and made the app bar…but I’m stuck at a place…please answer this so question http://stackoverflow.com/questions/33436398/how-to-autohide-v7-appbar-when-scrollin-hides-it-partially-android

    • Suleiman19 says:

      Hi Gundeep,

      The latest Design Support library added a new scroll flag ‘snap. Add it to your Toolbar’s layout_scrollFlags.

      The same answer is already suggested by a user on StackOverflow. 🙂

Leave a Reply

Your email address will not be published. Required fields are marked *