Android View Tutorial - Tablayout and ViewPager
Quick Links

I’m happy to say that the Android gods won’t be throwing us any curveballs today. Making Tabs in Android is bloody easy now; especially if you’re okay sticking with a Material Design aesthetic. Things will be a little more complicated in the next lesson where we combine our TabLayout with a ViewPager, but that’s about as far as we’ll go.

Basic Tablayout

Check out the video here.
1. Create a new project in AS called TabDemo (or whatever you want).  If using gradle (which you should be), open up your App level build.gradle file, and add the following lines to your dependencies:

compile 'com.android.support:appcompat-v7:24.2.0'
compile 'com.android.support:design:24.2.0'

If not using gradle, make sure you have the design library imported into your project.

2. Create an empty Activity called BasicTabActivity, and a corresponding Layout called activity_basic_tab.xml. The main component of Tabs in Android, is the TabLayout. It allows you to style your Tabs and even manipulate them at runtime. In the App, we have a TextView which changes its text each time the user clicks on a Tab. Go ahead and add a TabLayout and a TextView to the layout, like so:

activity_basic_tab.xml:

 
	<?xml version="1.0" encoding="utf-8"?>
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.wiseass.tabdemo.BasicTabActivity">

     <android.support.design.widget.TabLayout
        android:id="@+id/tbl_basic"
        android:layout_height="wrap_content"
        android:layout_width="match_parent">

         <!--You can create tabs in xml, but I personally prefer to add them
        in the java code. More flexibility that way.
         <android.support.design.widget.TabItem
            android:text="Music"
            />
         <android.support.design.widget.TabItem
            android:text="Movies"/>-->

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

     <TextView
        android:id="@+id/lbl_basic_content"
        android:layout_below="@id/tbl_basic"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:textColor="@android:color/black" />

 </RelativeLayout>

I’ve left some comments in the xml regarding adding tabs via xml. I wouldn’t suggest since I haven’t run in to a situation which didn’t require styling my tabs in the java code anyway, but you can use your own discretion here.

3.  Next, we’ll bang out our Activity. All we’re really doing, is creating the Tabs, styling them, then setting up our Listener. Nothing really special going on here:

 
	public class BasicTabActivity extends AppCompatActivity implements TabLayout.OnTabSelectedListener{

    private TabLayout tabarnak;
    private TextView content;

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

        getSupportActionBar().setElevation(0f);

        content = (TextView)findViewById(R.id.lbl_basic_content);

        tabarnak = (TabLayout)findViewById(R.id.tbl_basic);

        //create new tabs and set titles
        tabarnak.addTab(tabarnak.newTab().setText("Movies"));
        tabarnak.addTab(tabarnak.newTab().setText("Music"));


        tabarnak.setTabTextColors(ContextCompat.getColor(this, android.R.color.white),
                ContextCompat.getColor(this, R.color.colorAccent));
        tabarnak.setBackgroundColor(ContextCompat.getColor(this, R.color.colorPrimary));

        tabarnak.addOnTabSelectedListener(this);
    }


    @Override
    public void onTabSelected(TabLayout.Tab tab) {
        content.setText(tab.getText().toString());
    }

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

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

4. That’s the basics. You may be wondering, what if I want my tabs to look drastically different from whatever options I’m afforded by the basic Android APIs? Other than finding a Library, you can also supply each Tab with it’s own custom layout. Checkout the TabLayout.Tab section in the Android Docs. Cheers.

Tablayout w/ ViewPager and Fragments

Check out the video here.
1. We’ll start by creating a new Activity and Layout based on our old layout.

Open up your main package in the Project Explorer, and create a copy of BasicTabActivity in the same package. Call this new file ViewPagerActivity.

Open up res/layout and create a copy of activity_basic_tab.xml. Call it activtiy_view_pager.

Open up your project’s AndroidManifest, and create an entry for our newly created Activity. Important! We need to move our tag to the newly created tag. This will ensure that our App loads the ViewPager Activity when it is run. Since we won’t be bothering to code a way to navigate the App within the App itself, we must make this change. AndroidManifest.xml:

 
	<?xml version="1.0" encoding="utf-8"?>
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.wiseass.tabdemo">

     <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
         <activity android:name=".BasicTabActivity">

         </activity>

         <activity android:name=".ViewPagerActivity">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />

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

 </manifest>

2. Pull up activity_view_pager.xml. We’ll start by removing the TextView (we’ll have one in the our Fragment), and wrapping our TabLayout within a ViewPager tag, as suggested in the docs.

 
	<?xml version="1.0" encoding="utf-8"?>
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.wiseass.tabdemo.BasicTabActivity">

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

         <!--layout_gravity specifies where the TabLayout is drawn within the ViewPager. -->
     <android.support.design.widget.TabLayout
        android:id="@+id/tbl_main_content"
        android:layout_height="wrap_content"
        android:layout_width="match_parent"
        android:layout_gravity="top"
        
        />
     </android.support.v4.view.ViewPager>

 </RelativeLayout>

3. Let’s sort out our Fragment situation. Create a new Fragment in our main package called ViewPagerItemFragment. This Fragment will represent an individual item of our ViewPager. Nothing really fancy going on here; it’s just a plain Fragment. ViewPagerItemFragment.java:

 
	public class ViewPagerItemFragment extends Fragment {
    private static final String PAGE_TITLE = "PAGE_TITLE";

    private String pageTitle;
    private FragmentPagerItemCallback callback;

    public ViewPagerItemFragment(){}

    public static ViewPagerItemFragment getInstance(String pageTitle){
        ViewPagerItemFragment fragment = new ViewPagerItemFragment();
        Bundle args = new Bundle();
        args.putString(PAGE_TITLE, pageTitle);
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getArguments() != null) {
            this.pageTitle = getArguments().getString(PAGE_TITLE);
        } else {
            Log.d("TAG", "Well... F***.");
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.fragment_view_pager_item, container, false);
        TextView content = ((TextView)v.findViewById(R.id.lbl_pager_item_content));
        content.setText(pageTitle);
        content.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                callback.onPagerItemClick(
                        ((TextView)v).getText().toString()
                );
            }
        });

        return v;
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        if (context instanceof FragmentPagerItemCallback) {
            callback = (FragmentPagerItemCallback) context;
        } else {
            throw new RuntimeException(context.toString()
                    + " must implement FragmentPagerItemCallback");
        }
    }

    @Override
    public void onDetach() {
        super.onDetach();
        callback = null;
    }

    public interface  FragmentPagerItemCallback {
        void onPagerItemClick(String message);
    }
}

fragment_view_pager_item.xml:

 
	<?xml version="1.0" encoding="utf-8"?>
 <FrameLayout android:id="@+id/cont_pager_item_root"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >
     <TextView
        android:id="@+id/lbl_pager_item_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        />
 </FrameLayout>

4. All we need to do now is finish off our Activity. There’s quite a bit of stuff going on here; I’d suggest watching the video for more detail. Most importantly, note that we are using the TabLayout.setupWithViewPager(ViewPager) method to create our tabs. In order for this method to work, we must also Override CustomAdapter’s getPageTitle(int position) method. This is where our Tab’s titles are assigned.

Make the following changes to ViewPagerActivity.java:

 
	public class ViewPagerActivity extends AppCompatActivity implements TabLayout.OnTabSelectedListener,
ViewPagerItemFragment.FragmentPagerItemCallback{

    private TabLayout tabarnak;
    private ViewPager pager;

    private static final String[] pageTitles = {"Movies", "Music", "Podcasts", "Other"};

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

        getSupportActionBar().setElevation(0f);

        tabarnak = (TabLayout)findViewById(R.id.tbl_main_content);
        pager = (ViewPager)findViewById(R.id.vpg_main_content);
        setUpPagerAndTabs();

    }

    private void setUpPagerAndTabs(){
        tabarnak.setTabTextColors(ContextCompat.getColor(this, android.R.color.white),
                ContextCompat.getColor(this, R.color.colorAccent));
        tabarnak.setBackgroundColor(ContextCompat.getColor(this, R.color.colorPrimary));

        CustomAdapter adapter = new CustomAdapter(getSupportFragmentManager());
        pager.setAdapter(adapter);

        tabarnak.addOnTabSelectedListener(this);
        tabarnak.setupWithViewPager(pager);
    }

    @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) {
    }

    @Override
    public void onPagerItemClick(String message) {
        Toast.makeText(this, message + "!", Toast.LENGTH_SHORT).show();
    }

    /*For Pagers with a smaller/static number of pages, use FragmentPagerAdapter. It keeps visited
    caches fragments which have been opened in memory. If you require a large/dynamic number
    of pages, use FragmentStatePagerAdapter instead.
    */
    public static class CustomAdapter extends FragmentPagerAdapter{

        public CustomAdapter (FragmentManager manager){
            super(manager);
        }

        @Override
        public Fragment getItem(int position) {
            return ViewPagerItemFragment.getInstance(pageTitles[position]);
        }

        @Override
        public int getCount() {
            return pageTitles.length;
        }

        @Override
        public CharSequence getPageTitle(int position){
            return pageTitles[position];
        }
    }
}

That should be it. Cheers!