Material Design TabLayout and Toolbar animation (show/hide) when scrolling screen

    In previous post, I have presented the expanding/collapsing animations with Toolbar when scrolling the screen (the screen's content is RecyclerView or NestedScrollView). Today, I will talk about a popular layout: Tab bar. With TabLayout of Design Support Library, you can make a swipe view with tab easily. Now, by this post, I present  how to hiding/showing it and Toolbar (work as Action Bar) when your content can be scrolled.

Prerequisites

    Firstly, in order to use these widget, adding Design Support Library dependency into your module build.gradle:
compile 'com.android.support:design:23.4.0'
Make sure that you use a "no Action Bar theme" for your project:
styles.xml
<resources>

    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>

    <style name="MyCustomTabLayout" parent="Widget.Design.TabLayout">
        <item name="tabTextAppearance">@style/MyCustomTabText</item>
        <item name="tabBackground">@drawable/tab_layout</item>
        <item name="tabSelectedTextColor">#ff0000</item>
    </style>

    <style name="MyCustomTabText" parent="TextAppearance.AppCompat.Button">
        <item name="android:textSize">13sp</item>
        <item name="android:textAllCaps">false</item>
        <item name="android:textColor">@android:color/holo_blue_dark</item>
    </style>

</resources>
    I will use MyCustomTabLayout for styling the TabLayout then.

Hide TabLayout and Toolbar when scroll

    Now, follow these steps in designing layout (xml file), we will set both TabLayout and Toolbar are hidden when user scroll screen:
  • Make CoordinatorLayout as the root view.
  • Wrapping Toolbar and TabLayout in AppBarLayout.
  • Adding app:layout_scrollFlags="scroll|enterAlways" attribute to Toolbar and TabLayout.
  • Adding  app:layout_behavior="@string/appbar_scrolling_view_behavior" to ViewPager. This attribute will trigger event in the Toolbar.
    And we have the activity layout like this:
activity_main.xml
<android.support.design.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="wrap_content">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/ThemeOverlay.AppCompat.Dark">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            app:layout_scrollFlags="scroll|enterAlways" />

        <android.support.design.widget.TabLayout
            android:id="@+id/tab_layout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/colorPrimary"
            app:layout_scrollFlags="scroll|enterAlways" />
    </android.support.design.widget.AppBarLayout>

    <android.support.v4.view.ViewPager
        android:id="@+id/view_pager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</android.support.design.widget.CoordinatorLayout>
    In programmatically code, we'll populating tabs and do another necessary works. This is activity full source:
MainActivity.java
package info.devexchanges.tablayout;

import android.os.Bundle;
import android.support.design.widget.TabLayout;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;

public class MainActivity extends AppCompatActivity {

    private Toolbar toolbar;
    private TabLayout tabLayout;
    private ViewPager viewPager;

    private void findViews() {
        toolbar = (Toolbar) findViewById(R.id.toolbar);
        tabLayout = (TabLayout) findViewById(R.id.tab_layout);
        viewPager = (ViewPager) findViewById(R.id.view_pager);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_tab);
        findViews();
        setSupportActionBar(toolbar);

        //create and set ViewPager adapter
        ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
        viewPager.setAdapter(adapter);

        //create tabs title
        tabLayout.addTab(tabLayout.newTab().setText("Fragment 1"));
        tabLayout.addTab(tabLayout.newTab().setText("Fragment 2"));

        //attach tab layout with ViewPager
        //set gravity for tab bar
        tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
        tabLayout.setTabMode(TabLayout.MODE_FIXED);

        //change selected tab when viewpager changed page
        viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));

        //change viewpager page when tab selected
        tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
            @Override
            public void onTabSelected(TabLayout.Tab tab) {
                viewPager.setCurrentItem(tab.getPosition());
            }

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

            }

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

            }
        });
    }

    private class ViewPagerAdapter extends FragmentPagerAdapter {

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

        @Override
        public Fragment getItem(int position) {
            return new ContentFragment();
        }

        @Override
        public int getCount() {
            return 2;
        }
    }
}
    And code for each Fragment:
ContentFragment.java
package info.devexchanges.tablayout;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class ContentFragment extends Fragment {

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_content, container, false);
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
    }
}
The Fragment's layout:
fragment_conent.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="@dimen/activity_horizontal_margin"
        android:text="@string/lorem_ipsum" />

</android.support.v4.widget.NestedScrollView>
    Running app, we have this output:

Hide Toolbar and keep TabLayout

    Removing app:layout_scrollFlags attribute from TabLayout, we'll done this requirement:

Hide TabLayout and keep Toolbar when scroll

    This requirement is a bit more difficult. We should wrap TabLayout in CollapsingToolbarLayout, putting Toolbar and TabLayout in to 2 separated AppBarLayouts:
activity_main.xml
<RelativeLayout 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">

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

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            app:layout_collapseMode="pin"
            app:layout_scrollFlags="scroll|exitUntilCollapsed" />
    </android.support.design.widget.AppBarLayout>

    <android.support.design.widget.CoordinatorLayout
        android:id="@+id/main_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@id/id_toolbar_container">

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

            <android.support.design.widget.CollapsingToolbarLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                app:layout_scrollFlags="scroll|enterAlways">

                <android.support.design.widget.TabLayout
                    android:id="@+id/tab_layout"
                    android:layout_width="match_parent"
                    android:layout_height="?attr/actionBarSize" />
            </android.support.design.widget.CollapsingToolbarLayout>

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

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

    </android.support.design.widget.CoordinatorLayout>
</RelativeLayout>
And this is output:

Conclusions

    In this tip, I've present some options for Toolbar and TabLayout. This is often called scrolling techniques of Material Design (please read my previous post to know more). From this, I hope that readers can choose a suitable scrolling style with your Action Bar and Tab bar in your own application. Finally, thanks for reading!

Share


Previous post
« Prev Post
Next post
Next Post »