Android TabLayout with Gradient Indicator

Leonardo Vinsen
2 min readApr 6, 2019

Recently I was tasked with creating a tab with a gradient colored indicator. I had tried a third-party library and the Support Library TabLayout to get the desired design, but to no avail. At one point I was overriding the onDraw methods to draw my own indicator using Paint and LinearGradient shader, but apparently the gradient was drawn into the TabLayout background instead of the indicator.

In the end, I came up with an idea to create a custom view with a gradient drawable and place it above the Tab Layout and compute a translation along the x-axis to “slide” it. For this article I have created a new Github project called GradientTabs and it looks like this:

TabLayout with custom indicator

To achieve the desired tab appearance, we need the following:

  • A TabLayout with tabIndicatorColor set to null.
  • A View with gradient background,
  • A ViewPager (we will be using ViewPager.OnPageChangeListener to compute the translation),
  • And a FragmentPagerAdapter for the ViewPager.

Let’s start coding!

Libraries needed

Add these two libraries to your app build.gradle:

implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support:design:28.0.0'

Drawables

First one is the background for the indicator, gradient_bg.xml:

<?xml version="1.0" encoding="utf-8"?>
<shape
android:shape="rectangle"
xmlns:android="http://schemas.android.com/apk/res/android"
>

<corners android:radius="25dp"/>
<gradient
android:type="linear"
android:angle="45"
android:startColor="@color/colorPrimaryDark"
android:endColor="@color/colorPrimary"
/>
</shape>

Let’s give our TabLayout a nice outline by creating a drawable named tab_bg.xml:

<?xml version="1.0" encoding="utf-8"?>
<shape android:shape="rectangle"
xmlns:android="http://schemas.android.com/apk/res/android"
>
<corners android:radius="25dp"/>
<stroke android:color="@color/colorPrimaryDark" android:width="1dp"/> <solid android:color="#00000000"/>

</shape>

And finally the layout of our activity, activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity"
>

<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="32dp"
android:clipToPadding="false"
>

<View
android:id="@+id/indicator"
android:layout_width="0dp"
android:layout_height="50dp"
android:background="@drawable/gradient_bg"
/>

<android.support.design.widget.TabLayout
android:id="@+id/tab"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@drawable/tab_bg"
app:tabGravity="fill"
app:tabMode="fixed"
app:tabSelectedTextColor="#ffffff"
app:tabIndicatorColor="@null"
app:tabRippleColor="@null"
/>

</FrameLayout>

<android.support.v4.view.ViewPager
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>


</LinearLayout>

Note that the indicator’s layout_width is set to 0dp. We will assign it at runtime with the measured width of the TabLayout divided by number of tabs.

Code

Let’s start putting the pieces together. I have written simple FragmentPagerAdapter and Fragment classes to demonstrate that the custom indicator does follow scroll gestures:

FragmentPagerAdapter and Fragment classes

And lastly the logic to determine the translation:

And here’s the output:

Clicking on tab (left) and Sliding the viewpager (right)

I hope someone will find this useful and if you have any suggestions please leave a comment below. Happy coding! :)

--

--