Android Tip: Synchronously Animating Toolbar, TabLayout, and StatusBar Background Colors

Android Tip: Synchronously Animating Toolbar, TabLayout, and StatusBar Background Colors

    As you can see on Google Play application, when you change selected tab on the main screen (which has 2 tabs: App & Game and Books), the TabLayout, Toolbar and Status bar background color are also changed with an animation. This effect is look like this:

    By using TabLayout widget of Design Support Library, we can make this effect easily.
    Basically, within the onTabSelected() method of my TabLayout.OnTabSelectedListener implementation, I wanted to animate from the current color to the new tab’s corresponding color, ensuring that all views are animating simultaneously. Call this interface through addOnTabSelectedListener():
tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
            @Override
            public void onTabSelected(TabLayout.Tab tab) {
                //Add more code in this method later
            }

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

            }

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

            }
    To do this, I chose to use the ValueAnimator which allows you to iterate over the difference of two values over a timed interval. I also used an ArgbEvaluator for the ValueAnimator’s evaluator to handle the calculation of each animation step between the two ARGB colors:
int colorFrom = ((ColorDrawable) toolbar.getBackground()).getColor();
int colorTo = getColorForTab(tab.getPosition());
    We use the toolbar’s current background color as the starting color of the animation, and determine the color to animate to based on the newly selected tab.
    Now the ValueAnimator can be used to inform us of what color to use during each animation iteration:
colorAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator animator) {
                        int color = (int) animator.getAnimatedValue();

                        toolbar.setBackgroundColor(color);
                        tabLayout.setBackgroundColor(color);

                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                            getWindow().setStatusBarColor(color);
                        }
                    }

                });
colorAnimation.start();
    In order to setting the animation duration, you can use this code before call colorAnimation.start():
colorAnimation.setDuration(1000); //time in milliseconds
Finally, we have full code for this main activity:
MainActivity.java
package info.devexchanges.synchronouslycolor;

import android.animation.ArgbEvaluator;
import android.animation.ValueAnimator;
import android.graphics.drawable.ColorDrawable;
import android.os.Build;
import android.os.Bundle;
import android.support.design.widget.TabLayout;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;

public class MainActivity extends AppCompatActivity {

    private TabLayout tabLayout;
    private Toolbar toolbar;
    private String[] colors = {"Red", "Blue", "Green", "Yellow", "Gray"};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        tabLayout = (TabLayout) findViewById(R.id.tab_layout);
        toolbar = (Toolbar) findViewById(R.id.toolbar);

        setSupportActionBar(toolbar);

        for (String color : colors) {
            tabLayout.addTab(tabLayout.newTab().setText(color));
        }

        tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
        tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
            @Override
            public void onTabSelected(TabLayout.Tab tab) {
                int colorFrom = ((ColorDrawable) toolbar.getBackground()).getColor();
                int colorTo = getColorForTab(tab.getPosition());

                ValueAnimator colorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), colorFrom, colorTo);
                colorAnimation.setDuration(1000);
                colorAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator animator) {
                        int color = (int) animator.getAnimatedValue();

                        toolbar.setBackgroundColor(color);
                        tabLayout.setBackgroundColor(color);

                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                            getWindow().setStatusBarColor(color);
                        }
                    }

                });
                colorAnimation.start();
                toolbar.setTitle(colors[tab.getPosition()].toUpperCase());
            }

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

            }

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

            }
        });
    }

    public int getColorForTab(int position) {
        if (position == 0) return ContextCompat.getColor(this, R.color.colorPrimary);
        else if (position == 1) return ContextCompat.getColor(this, R.color.blue);
        else if (position == 2) return ContextCompat.getColor(this, R.color.green);
        else if (position == 3) return ContextCompat.getColor(this, R.color.yellow);
        else return ContextCompat.getColor(this, R.color.gray);
    }
}
    And that’s all there is to it - we now have a good animation, make our app look more smoothly and prettier! This is full screen output:

    References:
Android tip: Tab bar without ViewPager (using Material Design widget) in Android

Android tip: Tab bar without ViewPager (using Material Design widget) in Android

    Sometimes, we would like to build a Tab bar below Action Bar in our application but  also the content view is not a swipe views. When user click in a tab, the content view will be changed (like Google Play home page). In this post, with TabLayout widget from Material Design, we can build this interface easily.

About previous tab design

    Previously, to making a tab layout, we will usePagerTitleStrip or PagerTabStrip in Android SDK or use an external library like ViewPagerIndicator. These methods have a features: always attaching the "tab widget" with a ViewPager, and in order to make this requirement, we must disable swipe feature of the ViewPager. Now, with Material design, we now use TabLayout widget, which can "stand alone" to build a tab bar and do not need a ViewPager anymore.

Sample project

    Activity layout:
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="info.devexchanges.tabbarwithoutviewpager.MainActivity">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="?attr/colorPrimary"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
        app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />

    <android.support.design.widget.TabLayout
        android:id="@+id/tab_layout"
        style="@style/MyCustomTabLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/colorPrimary"
        app:tabGravity="fill"
        app:tabMode="fixed" />

    <LinearLayout
        android:id="@+id/fragment_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" />
</LinearLayout>
    Because of using Toolbar, your app theme must be a "no action bar theme". I also put a custom style for TabLayout in styles-resource:
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="tabSelectedTextColor">@android:color/holo_green_dark</item>
    </style>

    <style name="MyCustomTabText" parent="TextAppearance.AppCompat.Button">
        <item name="android:textSize">14sp</item>
        <item name="android:textStyle">bold</item>
        <item name="android:textColor">@android:color/white</item>
    </style>
</resources>
    In activity programmatically code, creating tab items and handling their click event:
MainActivity.java

package info.devexchanges.tabbarwithoutviewpager;

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.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.widget.LinearLayout;

public class MainActivity extends AppCompatActivity {

    private TabLayout tabLayout;
    private LinearLayout container;

    @SuppressWarnings("ConstantConditions")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        tabLayout = (TabLayout) findViewById(R.id.tab_layout);
        container = (LinearLayout) findViewById(R.id.fragment_container);

        setSupportActionBar(toolbar);

        //create tabs title
        tabLayout.addTab(tabLayout.newTab().setText("Applications"));
        tabLayout.addTab(tabLayout.newTab().setText("Books"));
        tabLayout.addTab(tabLayout.newTab().setText("Games"));

        //replace default fragment
        replaceFragment(new ApplicationFragment());

        //handling tab click event
        tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
            @Override
            public void onTabSelected(TabLayout.Tab tab) {
                if (tab.getPosition() == 0) {
                    replaceFragment(new ApplicationFragment());
                } else if (tab.getPosition() == 1) {
                    replaceFragment(new BookFragment());
                } else {
                    replaceFragment(new GameFragment());
                }
            }

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

            }

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

            }
        });
    }

    private void replaceFragment(Fragment fragment) {
        FragmentManager fragmentManager = getSupportFragmentManager();
        android.support.v4.app.FragmentTransaction transaction = fragmentManager.beginTransaction();
        transaction.replace(R.id.fragment_container, fragment);

        transaction.commit();
    }
}
    As you can see, when each tab was clicked, we'll replace corresponding Fragment into a container layout. These are Fragments code:
GameFragment.java
package info.devexchanges.tabbarwithoutviewpager;

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;
import android.widget.ArrayAdapter;
import android.widget.ListView;

import java.util.ArrayList;

public class GameFragment extends Fragment {

    protected ArrayList<String> strings;
    private ListView listView;

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        strings = new ArrayList<>();
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_content, container, false);
        listView = (ListView) view.findViewById(R.id.list_view);
        setData();
        ArrayAdapter<String> adapter = new ArrayAdapter<>(getActivity(), android.R.layout.simple_list_item_1, strings);
        listView.setAdapter(adapter);

        return view;
    }

    protected void setData() {
        strings.add("Hallo 5");
        strings.add("Call of Duty 3");
        strings.add("CS GO");
        strings.add("FIFA 15");
        strings.add("Assassin Creed 3");
        strings.add("Angry Bird");
        strings.add("Dark Soul");
    }
}
BookFragment.java

package info.devexchanges.tabbarwithoutviewpager;

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

public class BookFragment extends GameFragment {

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        return super.onCreateView(inflater, container, savedInstanceState);
    }

    protected void setData() {
        strings.add("Gone with the wind");
        strings.add("Kafka on the shore");
        strings.add("Gone girl");
        strings.add("Coffin dancer");
        strings.add("Hannibal rising");
        strings.add("A Study In Scarlet");
        strings.add("Innocent in Death");
        strings.add("Sense And Sensibility");
        strings.add("Revenge Wears Prada");
    }
}
ApplicationFragment.java

package info.devexchanges.tabbarwithoutviewpager;

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

public class ApplicationFragment extends GameFragment {

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        return super.onCreateView(inflater, container, savedInstanceState);
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    protected void setData() {
        strings.add("Job Search");
        strings.add("Action Launcher 3");
        strings.add("7 Minutes Workout");
        strings.add("Hulu");
        strings.add("Camera 360");
        strings.add("Here");
        strings.add("VLC");
        strings.add("Khan Academy");
        strings.add("Dasher Messenger");
        strings.add("Next Lock Screen");
        strings.add("Google Drive");
    }
}
    And their layout:
fragment_content.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ListView
        android:id="@+id/list_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</LinearLayout>
    After running, we have this output:

Final thoughts

    I have presented the way to create a tab layout without using ViewPager using TabLayout. Through this tip, I hope that you have learned more about Material Design in Android. Moreover, you can read this post to understanding how to disable swipe of ViewPager and this post, to learned how to use ViewPagerIndicator library. Finally, downloading full code on @Github.

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

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!

Android Basic Training Course: Combining Navigation Drawer and ViewPager (with Tab) in one screen

    In Android development, Sliding menu (also known as Navigation Drawer) and tabs layout is two popular interfaces, using in many applications. We often think of combining two types of layouts within a single screen, with DrawerLayout, NavigationView, ViewPager and TabLayout, we can combine theme in one Activity with Material design style easily.
    DEMO VIDEO:

    Firstly, adding design support library dependency to use these Material design widgets:
app/build.gradle
apply plugin: 'com.android.application'

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.3"

    defaultConfig {
        applicationId "info.devexchanges.navvp"
        minSdkVersion 14
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile 'com.android.support:design:23.4.0' //design support library
    compile 'com.android.support:appcompat-v7:23.4.0' //appcompat library (default)
}

Designing Activity layout

    Our layout will be like this:
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"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="?attr/colorPrimary"
        android:minHeight="?attr/actionBarSize"
        app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
        android:theme="@style/ThemeOverlay.AppCompat.Dark"
        app:titleTextColor="@android:color/white" />

    <android.support.v4.widget.DrawerLayout
        android:id="@+id/drawerLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">

            <android.support.design.widget.TabLayout
                android:id="@+id/tab_layout"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_below="@+id/toolbar"
                android:background="#125688"
                android:minHeight="?attr/actionBarSize"
                android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />

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


        <android.support.design.widget.NavigationView
            android:id="@+id/nav_view"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_gravity="start"
            android:fitsSystemWindows="true"
            app:menu="@menu/drawer_menu" />

    </android.support.v4.widget.DrawerLayout>
</LinearLayout>
    As you can see, we must put a ViewPager and a TabLayout in the first child of DrawerLayout, it's will make a swipeable view with tabs later, and it's child is a NavigationView, it now is the official widget to make a Navigation Drawer!

Programmatically code

    In our main Activity, locating all views, setting adapter for ViewPager (containing some Fragments), attaching TabLayout with ViewPager. It's must implement OnNavigationItemSelectedListener interface to handling NavigationView item clicked event. Soure code is simple like this:
MainActivity.java
package info.devexchanges.navvp;

import android.content.Intent;
import android.support.design.widget.NavigationView;
import android.support.design.widget.TabLayout;
import android.support.v4.view.GravityCompat;
import android.support.v4.view.ViewPager;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import android.view.MenuItem;

public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener{

    private ViewPager viewPager;
    private DrawerLayout drawer;
    private TabLayout tabLayout;
    private String[] pageTitle = {"Fragment 1", "Fragment 2", "Fragment 3"};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        viewPager = (ViewPager)findViewById(R.id.view_pager);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        drawer = (DrawerLayout) findViewById(R.id.drawerLayout);

        setSupportActionBar(toolbar);

        //create default navigation drawer toggle
        ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, toolbar,
                R.string.navigation_drawer_open, R.string.navigation_drawer_close);
        drawer.addDrawerListener(toggle);
        toggle.syncState();

        //setting Tab layout (number of Tabs = number of ViewPager pages)
        tabLayout = (TabLayout) findViewById(R.id.tab_layout);
        for (int i = 0; i < 3; i++) {
            tabLayout.addTab(tabLayout.newTab().setText(pageTitle[i]));
        }

        //set gravity for tab bar
        tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);

        //handling navigation view item event
        NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
        assert navigationView != null;
        navigationView.setNavigationItemSelectedListener(this);

        //set viewpager adapter
        ViewPagerAdapter pagerAdapter = new ViewPagerAdapter(getSupportFragmentManager());
        viewPager.setAdapter(pagerAdapter);

        //change Tab selection when swipe ViewPager
        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) {

            }
        });
    }

    @Override
    public boolean onNavigationItemSelected(MenuItem item) {
        int id = item.getItemId();

        if (id == R.id.fr1) {
            viewPager.setCurrentItem(0);
        } else if (id == R.id.fr2) {
            viewPager.setCurrentItem(1);
        } else if (id == R.id.fr3) {
            viewPager.setCurrentItem(2);
        } else if (id == R.id.go) {
            Intent intent = new Intent(this, DesActivity.class);
            intent.putExtra("string", "Go to other Activity by NavigationView item cliked!");
            startActivity(intent);
        } else if (id == R.id.close) {
            finish();
        }

        drawer.closeDrawer(GravityCompat.START);
        return true;
    }

    @Override
    public void onBackPressed() {
        assert drawer != null;
        if (drawer.isDrawerOpen(GravityCompat.START)) {
            drawer.closeDrawer(GravityCompat.START);
        } else {
            super.onBackPressed();
        }
    }
}
    Customizing ViewPager adapter based on FragmentPagerAdapter or FragmentStatePagerAdapter:
ViewPagerAdapter.java
package info.devexchanges.navvp;

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;

public class ViewPagerAdapter extends FragmentPagerAdapter {

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

    @Override
    public Fragment getItem(int position) {
        if (position ==0) {
            return new Fragment1();
        } else if (position == 1) {
            return new Fragment2();
        } else return new Fragment3();
    }

    @Override
    public int getCount() {
        return 3;
    }
}
    There are source code of 3 Fragments in this project (the ViewPager's children):
Fragment1.java
package info.devexchanges.navvp;

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;
import android.widget.Button;
import android.widget.TextView;

public class Fragment1 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);
        Button button = (Button) view.findViewById(R.id.button);
        button.setVisibility(View.GONE);
        TextView textView = (TextView)view.findViewById(R.id.text_view);
        textView.setText("A TextView in Fragment");
    }
}
Fragment2.java
package info.devexchanges.navvp;

import android.content.Intent;
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;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;

public class Fragment2 extends Fragment {

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

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        ListView listView = (ListView) view.findViewById(R.id.list);
        String[] dummyStrings = getResources().getStringArray(R.array.my_items);

        ArrayAdapter<String> adapter = new ArrayAdapter<>(getActivity(), android.R.layout.simple_list_item_1, dummyStrings);
        listView.setAdapter(adapter);

        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Toast.makeText(getActivity(), "You clicked at position: " + (position + 1), Toast.LENGTH_SHORT).show();
                Intent intent = new Intent(getActivity(), DesActivity.class);
                intent.putExtra("string", "go to another Activity from ListView position: " + (position + 1));
                startActivity(intent);
            }
        });
    }
}
Fragment3.java
package info.devexchanges.navvp;

import android.content.Intent;
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;
import android.widget.Button;

public class Fragment3 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);
        Button button = (Button) view.findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(getActivity(), DesActivity.class);
                intent.putExtra("string", "Go to other Activity from a ViewPager Fragment");
                startActivity(intent);
            }
        });
    }
}
Important Note: In this project, I use Toolbar as Action Bar, so the project theme is a "No Action Bar" theme:
styles.xml
<resources>

    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>

</resources>
    And the last is a destination Activity, getting here by clicking at the ListView item (in Fragment2), clicking a NavigationView item or clicking at the Button in Fragment3:
DesActivity.java
package info.devexchanges.navvp;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.MenuItem;
import android.widget.TextView;

public class DesActivity extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_des);

        Toolbar toolbar = (Toolbar)findViewById(R.id.toolbar);
        TextView textView = (TextView)findViewById(R.id.text_view);

        setSupportActionBar(toolbar);
        if (getIntent() != null) {
            textView.setText(getIntent().getStringExtra("string"));
        }

        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (item.getItemId() == android.R.id.home) {
            finish();
        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    public void onBackPressed() {
        finish();
    }
}

Running Application

Output will be like this:

When clicking at the a ListView item:

Go to destination activity from NavigationView's item clicked:

Go to destination activity from Fragment's element clicked:

Conclusions

    Through this post, I hope you can be learned about combining 2 powerful and popular widgets in developing Android application. Further, you can read this post  to understanding the solution which making tabs layout with Material design style and this post to learned about creating Navigation Drawer without NavigationView (more custom options). Thanks for reading and please subscribe my blog to get newest tutorials!



Android Material Design - ViewPager with Tabs using Design Support Library

    With with the appearance of Android Lollipop, a lot of new features released by Google. Along with that, support libraries system was published. The new Design Support Library was also included in the support repository. This new Android Design Support library provides a lot of new UI components like snackbars, floating action buttons and of-course it significantly improves the implementation of Android Tabs.
    Previously, to make tabs in Android, we will use PagerTabStrip widget in Android SDK or more flexible,  external libraries like PagerSlidingTabStrip, PagerIndicator,... are not a bad choice. But now with API 21 onwards, ActionBar has been deprecated. An alternative way to make tabs with full backward support was to use SlidingTabLayout and SlidingTabStrip classes. But now with Android Design Support Library, making swiping tabs has become even more simple. In this Android Tabs example, let's explore the power of new design support library.
Application Output
    In this post, I will prensent the way to make a simple project having a ViewPager with tab bar at top of screen with this new style. Now, create a new Android Project (min-sdk I use is 14).
    Before start, including these libraries in the dependencies section of your local build.gradle file (often located in 'app' module):
compile 'com.android.support:appcompat-v7:22.2.0'
compile 'com.android.support:design:22.2.0' // design support library
    We must customizing a theme based on "Theme.AppCompat.Light.NoActionBar" to use Material Design style. Open your styles.xml file and put this code:
   

Create a main activity to run

    As noted above, instead of ActionBar, we use Toolbar, and TabLayout is widget to make tab bar. Activity layout like this:
    In programmatically code, when user click at each tab, ViewPager will switch to corresponding screen, so add a TabLayout.OnTabSelectedListener method to handle this action:
private TabLayout.OnTabSelectedListener onTabSelectedListener(final ViewPager pager) {
        return new TabLayout.OnTabSelectedListener() {
            @Override
            public void onTabSelected(TabLayout.Tab tab) {
                pager.setCurrentItem(tab.getPosition());
            }

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

            }

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

            }
        };
    }
    Set "page changed listener" for ViewPager and use above method with these lines (often put after set ViewPager adapter):
viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
tabLayout.setOnTabSelectedListener(onTabSelectedListener(viewPager));
    Now, we have full code for activity and styles resources:
package devexchanges.info.viewpagertabsmd;

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

public class MainActivity extends AppCompatActivity {

    private final int numOfPages = 4; //viewpager has 4 pages
    private final String[] pageTitle = {"Food", "Movie", "Shopping", "Travel"};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout);

        for (int i = 0; i < numOfPages; i++) {
            tabLayout.addTab(tabLayout.newTab().setText(pageTitle[i]));
        }

        //set gravity for tab bar
        tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);

        final ViewPager viewPager = (ViewPager) findViewById(R.id.pager);
        final PagerAdapter adapter = new PagerAdapter
                (getSupportFragmentManager(), numOfPages);

        viewPager.setAdapter(adapter);
        viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
        tabLayout.setOnTabSelectedListener(onTabSelectedListener(viewPager));
    }

    private TabLayout.OnTabSelectedListener onTabSelectedListener(final ViewPager pager) {
        return new TabLayout.OnTabSelectedListener() {
            @Override
            public void onTabSelected(TabLayout.Tab tab) {
                pager.setCurrentItem(tab.getPosition());
            }

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

            }

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

            }
        };
    }
}


    

    

    


Create a ViewPager adapter

    We can customizing a ViewPager adapter based on FragmentStatePagerAdapter or FragmentPagerAdapter, declaring number of pages in it's constructor simple like this:
package devexchanges.info.viewpagertabsmd;

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;

public class PagerAdapter extends FragmentStatePagerAdapter {
    int numOfTabs;

    public PagerAdapter(FragmentManager fm, int numOfTabs) {
        super(fm);
        this.numOfTabs = numOfTabs;
    }

    @Override
    public Fragment getItem(int position) {

       return TabFragment.getInstance(position);
    }

    @Override
    public int getCount() {
        return numOfTabs;
    }
}

Create Fragments (Pages)

    Okey, I use a "mutual code" for all pages (Fragment), based on each page position, it's content has been changed! Programmatically code:
package devexchanges.info.viewpagertabsmd;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

public class TabFragment extends Fragment {

    private int position;
    private TextView content;
    private ImageView image;

    public static Fragment getInstance(int position) {
        TabFragment f = new TabFragment();
        Bundle args = new Bundle();
        args.putInt("position", position);
        f.setArguments(args);
        return f;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //get data from Argument
        position = getArguments().getInt("position");
    }

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

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        image = (ImageView) view.findViewById(R.id.image);
        content = (TextView) view.findViewById(R.id.textView);
        setContentView();
    }

    private void setContentView() {
        if (position == 0) {
            //food fragment
            image.setImageResource(R.mipmap.food);
            content.setText("This is Food Fragment");
        } else if (position == 1) {
            //movie fragment
            image.setImageResource(R.mipmap.movie);
            content.setText("This is Movie Fragment");
        } else if (position == 2) {
            //shopping fragment
            image.setImageResource(R.mipmap.shopping);
            content.setText("This is Shopping Fragment");
        } else {
            //travel fragment
            image.setImageResource(R.mipmap.travel);
            content.setText("This is Travel Fragment");
        }
    }
}
    And it's layout:

Running Application


Coming here, we have completed code, run this application (app module), we will see our result similar with this:


ViewPager with bottom Tabs Bar in Android

ViewPager with bottom Tabs Bar in Android

 
    In previous post, I had presented the way to customizing tabs bar at bottom of screen. The fact that there are many availabled libraries to make tab bar in ViewPager more flexible. Okey, in this tip, I will show how to use Jake Wharton ViewPager Indicator libary to customize your tab bar!

  1. Download library from Github, import library project in to your eclipse workspace:



2. Make it is a library project

After import completed, right click at project name (library), select Properties/Android... and checking at "is Library":


3. Make reference between your project with it

Right click at your project name, select Properties/Android, click at button Add... to make reference:

4. Coding an activity to run

In our Activity, there are a ViewPager with it's tab indicator. Layout (activity_pager.xml) like this:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

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

    <com.viewpagerindicator.TabPageIndicator
        android:id="@+id/tabs"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@android:color/holo_blue_bright"
        android:layout_alignParentBottom="true" />

</RelativeLayout>
As you can see, always use RelativeLayout, define indicator after  ViewPager and align it at bottom of screen to making this effect!
Java source code for PageActivity.java:
package com.blogspot.hongthaiit.viewpagerwithtabs;

import java.util.ArrayList;

import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.view.ViewPager;

import com.viewpagerindicator.TabPageIndicator;

public class PageActivity extends FragmentActivity {

 private CustomPagerAdapter customPagerAdapter;
 private ViewPager pager;
 private TabPageIndicator indicator;
 private ArrayList listIcon;
 private ArrayList fragmentContents;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_pager);

  getTabsIcon();
  customPagerAdapter = new CustomPagerAdapter(
    getSupportFragmentManager(), listIcon, fragmentContents);

  pager = (ViewPager) findViewById(R.id.pager);
  pager.setAdapter(customPagerAdapter);

  indicator = (TabPageIndicator) findViewById(R.id.tabs);
  indicator.setTabIconLocation(TabPageIndicator.LOCATION_UP);
  indicator.setViewPager(pager);
 }

 private void getTabsIcon() {
  listIcon = new ArrayList();

  listIcon.add(R.drawable.music);
  listIcon.add(R.drawable.video);
  listIcon.add(R.drawable.food);
  listIcon.add(R.drawable.friends);

  fragmentContents = new ArrayList();
  fragmentContents.add("This is Musics Page");
  fragmentContents.add("This is Videos Page");
  fragmentContents.add("This is Foods Page");
  fragmentContents.add("This is Friends Page");
 }
}

5. Create a custom ViewPager adapter to manage fragments

CustomPagerAdapter.java
package com.blogspot.hongthaiit.viewpagerwithtabs;

import java.util.ArrayList;

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;

import com.viewpagerindicator.IconPagerAdapter;

public class CustomPagerAdapter extends FragmentPagerAdapter implements
  IconPagerAdapter {

 private ArrayList listIcon;
 private ArrayList pageContents;

 public CustomPagerAdapter(FragmentManager fm, ArrayList list,
   ArrayList content) {
  super(fm);
  this.listIcon = list;
  this.pageContents = content;
 }

 @Override
 public Fragment getItem(int position) {

  return PageFragment.getInstance(pageContents.get(position), position);
 }

 @Override
 public int getCount() {
  return 4;
 }

 @Override
 public CharSequence getPageTitle(int position) {
  if (position == 0) {
   return "Music";
  } else if (position == 1) {
   return "Video";
  } else if (position == 2) {
   return "Food";
  } else
   return "Friend";
 }

 @Override
 public int getIconResId(int index) {
  return listIcon.get(index);
 }

}

6. Declare each fragment of Viewpager

- Layout (fragment_page.xml):
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"/>
    
    <ImageView 
        android:id="@+id/image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_above="@+id/textView"
        android:layout_centerInParent="true"
        android:contentDescription="@string/app_name"
        />

</RelativeLayout>
- Java code (PageFragment.java):
package com.blogspot.hongthaiit.viewpagerwithtabs;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

public class PageFragment extends Fragment {
 
 private TextView description;
 private ImageView image;
 
 public static PageFragment getInstance(String titles, int postion) {
  PageFragment f = new PageFragment();
  Bundle args = new Bundle();
  f.setArguments(args);
  args.putString("page_title", titles);
  args.putInt("position", postion);
  
  return f;
 }
 @Override
 public View onCreateView(LayoutInflater inflater, ViewGroup container,
   Bundle savedInstanceState) {
  // Inflate the layout resource that'll be returned
  View rootView = inflater.inflate(R.layout.fragment_page, container,
    false);

  description = (TextView)rootView.findViewById(R.id.textView);
  image = (ImageView) rootView.findViewById(R.id.image);
  
  description.setText(getArguments().getString("page_title"));
  setImage();

  return rootView;
 }
 
 private void setImage() {
  int postion = getArguments().getInt("position");
  if (postion == 0) {
   image.setImageResource(R.drawable.ic_music);
  } else if (postion == 1) {
   image.setImageResource(R.drawable.ic_video);
  } else if (postion == 2) {
   image.setImageResource(R.drawable.ic_food);
  } else if (postion == 3) {
   image.setImageResource(R.drawable.ic_friend);
  }
 }
}

7. In order to tabs bar is more good looking, we must styled it

In res/values/styles.xml, put this code to make theme:
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="StyledIndicators" parent="@android:style/Theme.Light">
        <item name="vpiTabPageIndicatorStyle">@style/CustomTabPageIndicator</item>
    </style>

    <style name="CustomTabPageIndicator" parent="Widget.TabPageIndicator">
        <item name="android:background">@drawable/custom_tab_indicator</item>
        <item name="android:textAppearance">@style/CustomTabPageIndicator.Text</item>
        <item name="android:textColor">#FF555555</item>
        <item name="android:textSize">16sp</item>
        <item name="android:divider">@drawable/custom_tab_indicator_divider</item>
        <item name="android:dividerPadding">10dp</item>
        <item name="android:showDividers">middle</item>
        <item name="android:paddingLeft">8dp</item>
        <item name="android:paddingRight">8dp</item>
        <item name="android:fadingEdge">horizontal</item>
        <item name="android:fadingEdgeLength">8dp</item>
    </style>

    <style name="CustomTabPageIndicator.Text" parent="android:TextAppearance.Medium">
        <item name="android:typeface">monospace</item>
    </style>

</resources>

8. In res/drawable folder, make custom_tab_indicator.xml:

<?xml version="1.0" encoding="utf-8"?>

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- Non focused states -->
    <item android:state_focused="false" android:state_selected="false" android:state_pressed="false" android:drawable="@drawable/custom_tab_indicator_unselected" />
    <item android:state_focused="false" android:state_selected="true"  android:state_pressed="false" android:drawable="@drawable/custom_tab_indicator_selected" />

    <!-- Focused states -->
    <item android:state_focused="true" android:state_selected="false" android:state_pressed="false" android:drawable="@drawable/custom_tab_indicator_unselected_focused" />
    <item android:state_focused="true" android:state_selected="true"  android:state_pressed="false" android:drawable="@drawable/custom_tab_indicator_selected_focused" />

    <!-- Pressed -->
    <!--    Non focused states -->
    <item android:state_focused="false" android:state_selected="false" android:state_pressed="true" android:drawable="@drawable/custom_tab_indicator_unselected_pressed" />
    <item android:state_focused="false" android:state_selected="true"  android:state_pressed="true" android:drawable="@drawable/custom_tab_indicator_selected_pressed" />

    <!--    Focused states -->
    <item android:state_focused="true" android:state_selected="false" android:state_pressed="true" android:drawable="@drawable/custom_tab_indicator_unselected_pressed" />
    <item android:state_focused="true" android:state_selected="true"  android:state_pressed="true" android:drawable="@drawable/custom_tab_indicator_selected_pressed" />
</selector>

9. In AndroidManifest, use theme which you make in styles.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.blogspot.hongthaiit.viewpagerwithtabs"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="14"
        android:targetSdkVersion="21" />

    <application
        android:icon="@drawable/icon"
        android:allowBackup="true"
        android:label="ViewPagerIndicator Sample" >
        <activity
            android:name="com.blogspot.hongthaiit.viewpagerwithtabs.PageActivity"
            android:label="ViewPager With Tabs"
            android:theme="@style/StyledIndicators" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

10. Build and run program, we can see our result like this:


pic name pic name
Additional Information
This post is part of a series called Android TOP useful libraries
(sorry for having ads)