Android Tab with Swipe Views, ViewPager, FragmentPagerAdapter in Android Studio

Android Tab with Swipe Views, ViewPager, FragmentPagerAdapter in Android Studio

In this tutorial we are going to learn how to develop Android Tab with Swipe Views, ViewPager, FragmentPagerAdapter in Android Studio. We are going to use Android Studio in this tutorial since it contains a template for creating ActionBar Tabs with ViewPager.

Android Tab is a top navigation design pattern in android and it can be used in application like News App where news articles are place in categories.

You can learn more about android Tab and where it can be use in android application development in android developers guide.

I wrote another article that covers using android Tab with android Toolbar. If you are using the new Android ToolBar and want to use a Tab, I will suggest you read this tutorial on Android Tab with ToolBar.

We will go further to modify the Android Tab with Swipe Views so that it will suit what we want to achieve. We are going to create a Music Application that categorizes music genre into three different Tabs (RnB, Reggae and Rap.)

Now lets briefly show case what we will like to achieve in this android tutorial. The screen shot below represent the user interface.

Android Tab with Swipe Views, ViewPager, FragmentPagerAdapter in Android Studio

Before we start, the first thing I will do is to list the environment and tools I used in this android tutorial but feel free to use whatever environment or tools you are familiar with.

Windows 7

Android Studio

Sony Xperia ZL

Min SDK 14

Target SDK 19

To create a new android application project, following the steps as stipulated below.

Go to File menu

Click on New menu

Click on Android Application

Enter Project name: AndroidTabWithSwipe

Package: com.inducesmile.androidtabwithswipe

In the add Activity to mobile window pop-up, select Tab Activity and click continue

Android Tab with Swipe Views, ViewPager, FragmentPagerAdapter in Android Studio

Enter the name of the project as shown below.

Android Tab with Swipe Views, ViewPager, FragmentPagerAdapter in Android Studio

Keep other default selections.

Continue to click on next button until Finish button is active, then click on Finish Button

We will go further to describe the content of the files that our project has generated for us. But before then, we will update our build.gradle to add a dependency library for CardView. The updated version of our project build.gradle is as shown

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:22.2.0'
    compile 'com.android.support:cardview-v7:21.0.+'
}

The following files were created for our project.

1. MainActivity – this is the MainActivity for our project which will contain the Tab component.

2. activity_main.xml – this is the main layout. It contains a ViewPager that will house a FragmentPagerAdapter for each of the Tab View.

3. fragment_main.xml – this is the default layout file for the Fragment pages.

We are going to change some few things in the generated project. First we will create three different Fragment classes that will represent each of our three Tabs.

Secondly, in the MainActivity class, we will update the getItem(int position) of the FragmentPagerAdapter so that it will reflect the changes that we have made in our Fragment.

activity_main.xml

The activity_main.xml file contains the ViewPager. The instance of the ViewPager will holds the FragmentPagerAdapter that will bind the individual fragments.

<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/pager"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" />

PopMsuicFragment.java

We will not include the fragment_main.xml file generate by our project. We are going to create a new Fragment file called PopMusicFragment.java.

The file will inflate a layout which contains a GridView that will use a custom adapter to bind the music tracks under a particular category.

The getAllItemObject() method will return the data source we will use to bind to the individual items.

package inducesmile.com.androidtabwithswipe;

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.AdapterView;
import android.widget.GridView;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.List;

public class PopMusicFragment extends Fragment {

    public PopMusicFragment() {
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_pop_music, container, false);
        GridView gridview = (GridView)view.findViewById(R.id.gridview);

        List<ItemObject> allItems = getAllItemObject();
        CustomAdapter customAdapter = new CustomAdapter(getActivity(), allItems);
        gridview.setAdapter(customAdapter);

        gridview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Toast.makeText(getActivity(), "Position: " + position, Toast.LENGTH_SHORT).show();
            }
        });
        return view;
    }

    private List<ItemObject> getAllItemObject(){
        List<ItemObject> items = new ArrayList<>();
        items.add(new ItemObject(R.drawable.milian,"Dip It Low", "Christina Milian"));
        items.add(new ItemObject(R.drawable.adele,"Someone like you", "Adele Adkins"));
        items.add(new ItemObject(R.drawable.ciara,"Ride", "Ciara"));
        items.add(new ItemObject(R.drawable.gaga,"Paparazzi", "Lady Gaga"));
        items.add(new ItemObject(R.drawable.brown,"Forever", "Chris Brown"));
        items.add(new ItemObject(R.drawable.rihana,"Stay", "Rihanna"));
        items.add(new ItemObject(R.drawable.jason,"Marry me", "Jason Derulo"));
        items.add(new ItemObject(R.drawable.shakira,"Waka Waka", "Shakira"));
        items.add(new ItemObject(R.drawable.perry,"Dark Horse", "Katy Perry"));
        items.add(new ItemObject(R.drawable.milian,"Dip It Low", "Christina Milian"));
        items.add(new ItemObject(R.drawable.milian,"Dip It Low", "Christina Milian"));
        items.add(new ItemObject(R.drawable.milian,"Dip It Low", "Christina Milian"));
        return items;
    }

}

Fragment_pop_music.xml

The fragment_pop_music.xml is the layout file for the PopMusicFragment. It contains a GridView as shown below.

<?xml version="1.0" encoding="utf-8"?>
<GridView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/gridview"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:horizontalSpacing="4dp"
    android:numColumns="3"
    android:padding="4dp"
    android:scrollbars="none"
    android:stretchMode="columnWidth"
    android:verticalSpacing="4dp" />

We will obtain the GridView handler and attach a custom adapter. So let create a Custom Adapter. It will use the Holder Pattern to hold reference to three views that will contain the album cover, name and author.

package inducesmile.com.androidtabwithswipe;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;

import java.util.List;

public class CustomAdapter extends BaseAdapter {

    private LayoutInflater layoutinflater;
    private List<ItemObject> listStorage;
    private Context context;

    public CustomAdapter(Context context, List<ItemObject> customizedListView) {
        this.context = context;
        layoutinflater =(LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        listStorage = customizedListView;
    }

    @Override
    public int getCount() {
        return listStorage.size();
    }

    @Override
    public Object getItem(int position) {
        return position;
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        ViewHolder listViewHolder;
        if(convertView == null){
            listViewHolder = new ViewHolder();
            convertView = layoutinflater.inflate(R.layout.pop_music_list, parent, false);
            listViewHolder.screenShot = (ImageView)convertView.findViewById(R.id.screen_shot);
            listViewHolder.musicName = (TextView)convertView.findViewById(R.id.music_name);
            listViewHolder.musicAuthor = (TextView)convertView.findViewById(R.id.music_author);

            convertView.setTag(listViewHolder);
        }else{
            listViewHolder = (ViewHolder)convertView.getTag();
        }
        listViewHolder.screenShot.setImageResource(listStorage.get(position).getScreenShot());
        listViewHolder.musicName.setText(listStorage.get(position).getMusicName());
        listViewHolder.musicAuthor.setText(listStorage.get(position).getMusicAuthor());

        return convertView;
    }

    static class ViewHolder{
        ImageView screenShot;
        TextView musicName;
        TextView musicAuthor;
    }
}

The custom adapter will inflate a layout file that contains the views that we will bind our data source to. The layout file will contain an ImageView and two TextViews

<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:id="@+id/card_view"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    card_view:cardUseCompatPadding="true"
    card_view:cardCornerRadius="4dp"
    card_view:cardElevation="4dp">

    <RelativeLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="8dp">

        <ImageView
            android:id="@+id/screen_shot"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:contentDescription="@string/hello_world"
            android:layout_alignParentTop="true"
            android:scaleType="centerCrop"
            android:src="@drawable/milian"
            android:layout_centerHorizontal="true"/>

        <TextView
            android:id="@+id/music_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@+id/screen_shot"
            android:layout_alignLeft="@+id/screen_shot"
            android:text="@string/hello_world"
            android:inputType="text"
            android:textColor="#000"
            android:layout_marginTop="8dp"
            android:textSize="12sp"/>

        <TextView
            android:id="@+id/music_author"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@+id/music_name"
            android:layout_alignLeft="@+id/music_name"
            android:text="@string/hello_world"
            android:textSize="12sp"
            android:layout_marginTop="4dp"/>

    </RelativeLayout>
</android.support.v7.widget.CardView>

We will use the ListView instance to holder an entity object that will wrap on data. We will create the entity object as shown below.

package inducesmile.com.androidtabwithswipe;

public class ItemObject {

    private int screenShot;
    private String musicName;
    private String musicAuthor;

    public ItemObject(int screenShot, String musicName, String musicAuthor) {
        this.screenShot = screenShot;
        this.musicName = musicName;
        this.musicAuthor = musicAuthor;
    }

    public int getScreenShot() {
        return screenShot;
    }

    public String getMusicName() {
        return musicName;
    }

    public String getMusicAuthor() {
        return musicAuthor;
    }
}

MainActivity.java

Finally our MainActivity class will implement the ActionBar.TabListener  MainActivity extends AppCompatActivity implements ActionBar.TabListener.   We will get a handler for our ViewPager using the findViewById(int id) of the Activity class.

The class SectionsPagerAdapter extends FragmentPagerAdapter creates an inner class that extends from FragmentPagerAdapter.

The constructor takes a FragmentManager as a parameter.

The getItem(int position) override method will return a fragment instance of the page that is on focus.
The following methods are implemented from the ActionBar.TabListener

@Override
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
// When the given tab is selected, switch to the corresponding page in
// the ViewPager.
mViewPager.setCurrentItem(tab.getPosition());
}
@Override
public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
}
@Override
public void onTabReselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
}

The complete code for the class is as shown

package inducesmile.com.androidtabwithswipe;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.view.ViewPager;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuItem;

import java.util.Locale;


public class MainActivity extends AppCompatActivity implements ActionBar.TabListener {

    SectionsPagerAdapter mSectionsPagerAdapter;

    ViewPager mViewPager;

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

        // Set up the action bar.
        final ActionBar actionBar = getSupportActionBar();
        actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

        // Create the adapter that will return a fragment for each of the three
        // primary sections of the activity.
        mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());

        // Set up the ViewPager with the sections adapter.
        mViewPager = (ViewPager) findViewById(R.id.pager);
        mViewPager.setAdapter(mSectionsPagerAdapter);

        // When swiping between different sections, select the corresponding
        // tab. We can also use ActionBar.Tab#select() to do this if we have
        // a reference to the Tab.
        mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
            @Override
            public void onPageSelected(int position) {
                actionBar.setSelectedNavigationItem(position);
            }
        });

        // For each of the sections in the app, add a tab to the action bar.
        for (int i = 0; i < mSectionsPagerAdapter.getCount(); i++) {
            // Create a tab with text corresponding to the page title defined by
            // the adapter. Also specify this Activity object, which implements
            // the TabListener interface, as the callback (listener) for when
            // this tab is selected.
            actionBar.addTab(actionBar.newTab().setText(mSectionsPagerAdapter.getPageTitle(i)).setTabListener(this));
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    @Override
    public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
        // When the given tab is selected, switch to the corresponding page in
        // the ViewPager.
        mViewPager.setCurrentItem(tab.getPosition());
    }

    @Override
    public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
    }

    @Override
    public void onTabReselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
    }

    /**
     * A {@link FragmentPagerAdapter} that returns a fragment corresponding to
     * one of the sections/tabs/pages.
     */
    public class SectionsPagerAdapter extends FragmentPagerAdapter {

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

        @Override
        public Fragment getItem(int position) {
            Fragment fragment = null;
            switch(position){
                case 0:
                    fragment = new PopMusicFragment();
                    break;
                case 1:
                    fragment = new PopMusicFragment();
                    //fragment = new RaggaeMusicFragment();
                    break;
                case 2:
                    fragment = new PopMusicFragment();
                    //fragment = new RapMusicFragment();
            }
            return fragment;
        }

        @Override
        public int getCount() {
            // Show 3 total pages.
            return 3;
        }

        @Override
        public CharSequence getPageTitle(int position) {
            Locale l = Locale.getDefault();
            switch (position) {
                case 0:
                    return getString(R.string.title_section1).toUpperCase(l);
                case 1:
                    return getString(R.string.title_section2).toUpperCase(l);
                case 2:
                    return getString(R.string.title_section3).toUpperCase(l);
            }
            return null;
        }
    }

}

Now, when you run your application you will see the interface that looks similar to the sample that was shown earlier on.

You can download the code for this tutorial below. If you are having hard time downloading the tutorials, kindly contact me.

Remember to subscribe with your email so that you will be among the first to receive our new post once it is published.

OTHER INTERESTING POSTS:

5 Comments

Add a Comment