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.

Share


Previous post
« Prev Post
Next post
Next Post »