How We Implemented the Color Tabs Animation for Android

We have a lot of different recommended design patterns for Android development including embedded navigation, tabs, bottom navigation bar, navigation drawer, nested navigation, expanding navigation drawer, and gestural navigation. But sometimes we want to make ordinary things a bit special. That's why we worked hard on implementing our Color Tabs animation on Android.

The architecture of the ColorTabView is more difficult than it appears. We had to make it scalable and the architecture could be independent of the tab count. We chose HorizontalScrollView as a solution to this problem, and chose TabLayout as the template for this animation.

how-to-develop-the-colortab-animation-for-android

Based on this concept, the selected tab should be bigger than unselected tabs and should contain an icon and text. To implement this feature, we calculated the measurements for all layouts.

We needed to move the rectangle that’s behind the selected tab from one tab to the next. To solve this problem, we drew the background in SlidingTabStripLayout instead of in ColorTabView. To draw the background for the selected tab, we used Canvas and drew the background only for the selected child.

how-to-develop-the-colortab-animation-for-android

backgroundPaint = Paint()
backgroundPaint.flags = Paint.ANTI_ALIAS_FLAG
val rectangle = RectF(left, topY, right, selectedChild.height.toFloat())
canvas?.drawRoundRect(rectangle,radius,radius, backgroundPaint)

To implement the animation for this background, we chose ValueAnimator:

internal fun animateDrawTab(child: ColorTabView?) {
   ValueAnimator.ofFloat((parent as ColorMatchTabLayout).previousSelectedTab?.x ?: 0f, child?.x ?: 0f).apply {
       duration = 200L
       interpolator = PathInterpolatorCompat.create(firstControlX, firstControlY, secondControlX, secondControlY)

       addUpdateListener {
           animateLeftX = animatedValue as Float
           invalidate()
       }
      addListener(object : AnimatorListenerAdapter()  {

        override fun onAnimationEnd(animation: Animator?) {
             child?.clickedTabView = null
             isAnimate = false
        }

        override fun onAnimationStart(animation: Animator?) {
             isAnimate = true
        }
   })
   }.start()
}

One of the main requirements for creating an animation (in our case a bounce animation) is to create a custom interpolator. This can be created in two ways:

1. Create easing functions that draw the cubic bezier curve you require.

2. Create interpolators with just control points using PathInterpolatorCompat.

The second method was more suited to our purposes. We calculated the first and second control point of the cubic Bezier and passed it to the create() method of PathInterpolatorCompat.

interpolator = PathInterpolatorCompat.create(firstControlX, firstControlY, secondControlX, secondControlY)

Based on our animation concept, we had to change the icon and text color. To do this, we used ColorFilter:

iconView.setColorFilter(backgroundColor/selectedTabColor, PorterDuff.Mode.SRC_ATOP)

Now, developers can set white icons that will change color as follows:

- For the selected tab, the color of the icon and text will be the same as the background ColorMatchTabLayout;

- For unselected tabs, icons will be the same color as their backgrounds when selected.

ArcMenu

ArcMenu is an addition to ColorMatchTabLayout that developers can add to their screen. To implement this part of the component, we needed to:

  • Create a FAB (Floating Action Button)

  • Draw ArcMenu items so they were equidistant from the center of the circle

  • Animate opening and closing of ArcMenu items

  • Move down the tabs icon

  • Transpose icons from tabs to ArcMenu

  • Return icons to ColorTabView from the ArcMenu

The ArcMenu elements are circles drawn with Canvas. We redrew the icons from the ColorTabView to circles for the ArcMenu with the .draw(canvas) method. To transpose icons from ColorTabView to the ArcMenu, we calculated bounds and assigned those bounds to the icons.

It’s important to note that the ArcMenu doesn’t work as an independent element. A user needs to add this component to ColorMatchTabLayout. Also, this part of the animation works only with 3–5 tabs in ColorMatchTabLayout. With a different number of tabs, you get an InvalidNumberOfTabsException.

You can find our custom view implementation with overlapped content in our sample on Github:

how-to-develop-the-colortab-animation-for-android

Technology stack

We chose the Kotlin programming language as the tool for this job. Over the past year, we have published animations written in Kotlin. We love this language and love to please you with new animations written in it.

How to use ColorMatchTabs

To use ColorMatchTabs, add ColorMatchTabLayout to the XML layout of your activity. Also, please note that a ViewPager is also added, which should be attached to ColorMatchTabs in the activity below through the following code:


<RelativeLayout
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">

<com.yalantis.colormatchtabs.colormatchtabs.colortabs.ColorMatchTabLayout
   android:id="@+id/tabLayout"
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:layout_below="@+id/toolbar"
   android:background="?attr/colorPrimary"
   android:elevation="6dp"
   android:minHeight="?attr/actionBarSize"
   android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />

<android.support.v4.view.ViewPager
   android:id="@+id/pager"
   android:layout_width="match_parent"
   android:layout_height="fill_parent"
   android:layout_below="@id/tabLayout" />

</RelativeLayout>

In your onCreate() method, bind ColorMatchTabs and add it to tabs using the .addTab() method.

colorMatchTabLayout.addTab(ColorTabAdapter.createColorTab(colorMatchTabLayout, tabName, selectedColor, icon))
If you use an OnPageChangeListener with your ViewPager, you should set ColorTabLayoutOnPageChangeListener(colorMatchTabLayout) in the ViewPager rather than on the pager directly.
viewPager.addOnPageChangeListener(ColorTabLayoutOnPageChangeListener(tabLayout))

Customization

One of the most important feature of every custom view is the ability to customize its look as needed. By calling the following methods (or attributes), you can customize ColorMatchTabLayout as you need.

// to change unselected tab color you can change background color for all layouts
setBackgroundColor(color: Int) 

//Change selected tab color, icon and title of tab:
tab.selectedColor = color : Int
tab.icon = icon : Drawable
tab.text = iconTitle : String

//or change all these parameters
ColorTabAdapter.createColorTab(colorMatchTabLayout, tabName, selectedColor, icon)

//Set selected ColorTab width in portrait and horizontal orientations
selectedTabWidth, selectedTabHorizontalWidth

addArcMenu(arcMenu)

To change the selected tab, you can use the methods below:

//Set selected tab
selectedTabIndex: Int
selectedTab: Int

//Get the position of the current selected tab
selectedTabPosition : Int

//Return ColorTab at the specified index 
colorMatchTabLayout.getTabAt(index : Int)

ArcMenu is an addition to the ColorMatchTabLayout. To use ArcMenu, add it to the XML layout of your activity with the color tabs as shown below:

 <RelativeLayout 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"
   tools:context="com.yalantis.colormatchtabs.colortabs.MainActivity">

   <com.yalantis.colormatchtabs.colormatchtabs.colortabs.ColorMatchTabLayout
       android:id="@+id/colorMatchTabLayout"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:layout_below="@+id/toolbar"
       android:background="?attr/colorPrimary"
       android:elevation="6dp"
       android:minHeight="?attr/actionBarSize"
       android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />

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

   <com.yalantis.colormatchtabs.colormatchtabs.menu.ArcMenu
       android:id="@+id/arcMenu"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:layout_alignParentBottom="true"
       android:layout_centerHorizontal="true" />

</RelativeLayout>

After that, bind your ArcMenu and add it to ColorMatchTabLayout:

colorMatchTabLayout.addArcMenu(arcMenu)

You can find this ColorMatchTabLayout library and many more in our GitHub repository, and can check out our designs on Dribbble

You can also get a cool demo of our component on the Google Play Store.

4.9/ 5.0
Article rating
44
Reviews
Remember those Facebook reactions? Well, we aren't Facebook but we love reactions too. They can give us valuable insights on how to improve what we're doing. Whould you tell us how you feel about this article?