DesignLibrary / Material Design / TabLayout

Design Library – Part 2

At Google I/O 2015 the Material Design Support Library was announced, and with it creating material apps targeting API levels below API 19 suddenly got a lot easier. In this series we’ll look at taking the RSS Reader app that we used as a basis for the Material series, and re-write it to make full use of the new Design Support Library. Previously we looked at getting a basic navigation drawer working and in this post we’ll look at how to implement a tab bar.

ViewPager has been around for a while and is a well used and understood component, so I won’t bother with a full explanation of it here. But let’s begin with looking at the Fragment implementation that will represent each page in our ViewPager. The content of each item within the RSS feed is basic HTML so we’ll use a WebView to handle the rendering for us (Please don’t hate me for how horribly this renders – it is basic HTML without any CSS so it renders how it renders. The point of this article is about the stuff which happens around the content and not how the content itself is rendered).

Let’s look at the fragment layout:

That’s pretty straightforward, so let’s also take a look at the Fragment implementation:

Once again, this is pretty straightforward – an Item is passed in, and the content of this is rendered in the WebView. The only things worth noting are that we replace newlines with <br /> to improve the rendering slightly. Also we call setUseViewPortMode(true) and setLoadWithOverviewMote(true) to start things zoomed out (so that the entire width of the content is displayed). This is to remove any horizontal scrolling which will affect the operation of the ViewPager container. (once again, do’t hate me for this – the ViewPager is the focus of this article so we’ll fix the WebView rendering so as not to interfere with that).

Now that we have the individual pages for the ViewPager defined, let’s take a look at the Adapter which will connect these up to the ViewPager:

This is a pretty unremarkable Adapter implementation. The only thing worthy of note is the inclusion of a getPageTitle() implementation (where we generate a title in the form “Part X”). Anyone who has used PagerTitleStrip from the v4 support library will be familiar with this, and the new TabLayout implementation uses exactly the same mechanism to get the text to go in to each tab item.

Next we need to look at out main layout. Previously we defined a FrameLayout containing our Toolbar, but now we ned to add our TabLayout and ViewPager:

In here we’ve added our TabLayout – this control is going to do all of the hard work for us! We have a choice of operation modes – fixed, where the tabs are dynamically sized so that the TabLayout exactly fits the space available; and scrollable, where the tabs themselves are a fixed size, and if they exceed the space available the user will be able to scroll the tabs to get to them all.

A general rule of thumb is that if you have a relatively small number of tabs then fixed mode works really well, but a large number of tabs works best with scrollable. In this app the number of items in each article will vary and may sometimes be quite large (Dirty Phrasebook in the example videos consist of 6 parts), so I’ve gone for scrollable.

Because I elected to go with scrollable mode, I actually want the left hand edge of the first tab text to align to the title text in the Toolbar so I gave a left padding to achieve this. By setting android:clipToPadding="false" the tabs will scroll in to the blank area left by this margin when we scroll the tabs.

The only remaining component in the layout is our ViewPager.

All that remains is to wire this all together in our Activity:

All of the real work is done in setCurrentArticle() when a new Article is selected. First we set up a new ArticleViewPagerAdapter instance based on the new Article, and we apply this to the ViewPager. Next we do a quick check to either hide the TabLayout if there is only a single part in the article, or show it otherwise. Finally we hook the TabLayout to the ViewPager which initialises the tabs, and hooks up all of the paging / tab selection logic for us. That is one powerful method call!

If we run this we can see we have a fully implemented tab bar:

There is, however, one subtly problem here. The tab bar is supposed to have an indicator bar at the bottom of the selected tab. The reason that this is missing is because of the colorAccent value that we defined in our theme:

We’ve declared this as the same colour as our colorPrimary. colorPrimary will be used as the background colour of our AppBarLayout, and colorAccent will be used for the indicator bar colour. As these are the same, our indicator bar is not showing. For now we’ll set this to white (but this will cause us problems further down the line with our FloatingActionButton but we’ll deal with that when we get to it):

Now we have a working indicator bar:

That’s looking pretty good, but wouldn’t it be nice if we could do a very material-like thing and scroll the Toolbar away as we scroll down, and provide a quick return as the user scrolls back up? In the next article we’ll do precisely that.

The source code for this article is available here.

© 2015, Mark Allison. All rights reserved.

CC BY-NC-SA 4.0 Design Library – Part 2 by Styling Android is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. Permissions beyond the scope of this license may be available at http://blog.stylingandroid.com/license-information.

1 Comment

  1. Just a note that you can use app:tabContentStart on the TabLayout instead of android:clipToPadding and android:paddingLeft. This way you can use the proper keyline (72dp).

Leave a Reply

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