Android ActionBar SwipeTabs ViewPager - Fragments With GridViews

September 3, 2017 Oclemy Android ActionBar, Android ViewPager, Android Fragment, Android GridView 12 minutes, 21 seconds

It's important that we know how to construct applications that can be swiped. Alot of the times while interacting with apps you see the ability to swipe being integrated in modern applications.

This ability in android is enable by a class called android.support.v4.View.ViewPager.

ViewPager gives us this ability to swipe.

Moreover we may want our users to have the ability to click through the tabs and navigate appropriately the application. Users probably intuitively expect this.

So we make use of ActionBar Tabs. Tabs allow us to navigate pages/fragments by clicking them.

Here are the advantages of Tabs:

No. Advantage
1. They are easy to use and intuitive for users.
2. Tabs are very visible and accessible to users in that in android tabs are placed at the actionbar at the top.
3. Tab Navigation is instant. This is due to the fact that Tabs usually display Fragments and Fragments are typically hosted by activities so Fragments are quiter lighter than Activities.

What the App does

In this case our application will comprise three tabs.

Each Tab will display a Fragment and each Fragment will contain a gridview.

Each GridView will have it's own data. These data can be from any source but for simplicity sake we use a String array as our data source.

Each String array will contain a list of countries from Asian, African and European continents.

Our tab are actionbar tabs.

What is ActionBar

An actionbar is a primary toolbar normally appearing at the top of the activity's window.

Here are the main functions of an actionbar:

  1. Display the activity title.
  2. Allow for navigation throughout the whole application.
  3. Provide a consistent theming throughout the application irrespective of the activity.

Our Swipeable Fragments

We'll have three fragments that our users will be able to swipe through. The swiping functionality is enabled by the ViewPager class.

1. Asia Fragment

This is our Asia Fragment. It represents the Asian continent and it will containa gridview.

This GridView will display some of the countries within the asian continent.

We are going to hold these countries in a string array. So basically that array is our data source.

Here are the functions of this fragment:

No. Responsibility
1. Hold a String array containing Asian countries.
2. Define an [ArrayAdapter(/android/arrayadapter)] to adapt those countries to an adapterview.
3. Define a GridView to hold our Asian countries.
4. Override the onCreateView() method of the android.support.v4.app.Fragment class.
5. Inflate the R.layout.asia layout into our Fragment and return it in the onCreateView() method.
6. Instantiate our adapter and set it to our gridview.

Here's our source code.

    package com.tutorials.viewpagertabsgridview;

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

    public class Asia extends Fragment {

       String[] countries={"India","Pakistan","Malaysia","Bangladesh","Singapore","China","Syria","Saudi Arabia"};
       ArrayAdapter<String> adapter;
       GridView gv;

       @Override
      public View onCreateView(LayoutInflater inflater, ViewGroup container,
          Bundle savedInstanceState) {
        // TODO Auto-generated method stub
         View rootView=inflater.inflate(R.layout.asia, null);

         gv=(GridView) rootView.findViewById(R.id.gridView1);

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

         gv.setAdapter(adapter);

        return rootView;
      }

    }

2. Africa Fragment

This is our Africa Fragment. This Fragment will contain a Gridview that will contain our African counrtries.

As a class this fragment will derive from android.support.v4.app.Fragment making it a Fragment.

Here are the functions of this fragment:

No. Responsibility
1. Our Fragment will contain a gridview bound to a String array containing African countries.
2. Define an ArrayAdapter to adapt those countries to an adapterview.
3. Define a gridview to hold our African countries.
4. Override the onCreateView() method of the android.support.v4.app.Fragment class. This method is a fragment lifecycle callback that gets invoked when the Fragment's View is created.
5. Inflate the R.layout.africa layout into our Fragment and return it in the onCreateView() method.
6. Instantiate our adapter and set it to our gridview.

Here's the code:

    package com.tutorials.viewpagertabsgridview;

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

    public class Africa extends Fragment {

      String[] countries={"Kenya","Nigeria","Rwanda","South Africa","Egypt","Uganda","Zambia","Libya"};
       ArrayAdapter<String> adapter;
       GridView gv;

       @Override
      public View onCreateView(LayoutInflater inflater, ViewGroup container,
          Bundle savedInstanceState) {
        // TODO Auto-generated method stub
         View rootView=inflater.inflate(R.layout.africa, null);

         gv=(GridView) rootView.findViewById(R.id.gridView1);

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

         gv.setAdapter(adapter);

        return rootView;
      }

    }

3. Europe Fragment

This is our Europe Fragment. This European Fragment will contain a GridVoew that will hold our European countries.

That GridView will be bound to a string array as our data source. Normally these data binding requires an adapter so we will use an arrayadapter which is a child of BaseAdapter.

This European Fragment will derive from android.support.v4.app.Fragment making it a Fragment.

Here are the functions of this european fragment:

No. Responsibility
1. Hold a String array containing European countries. This String array will be our data source.
2. Define an ArrayAdapter to adapt those countries to an adapterview.
3. Define a GridView to hold our European countries. A GridView is an adapterview that holds data in a two dimensional format.
4. Override the onCreateView() method of the android.support.v4.app.Fragment class.
5. Inflate the R.layout.europe layout into our Fragment and return it in the onCreateView() method.

Let's have a look at our source code.

    package com.tutorials.viewpagertabsgridview;

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

    public class Europe extends Fragment{

      String[] countries={"England","Germany","Spain","Belgium","France","Italy","Ireland","Holland"};
       ArrayAdapter<String> adapter;
       GridView gv;

       @Override
      public View onCreateView(LayoutInflater inflater, ViewGroup container,
          Bundle savedInstanceState) {
        // TODO Auto-generated method stub
         View rootView=inflater.inflate(R.layout.europe, null);

         gv=(GridView) rootView.findViewById(R.id.gridView1);

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

         gv.setAdapter(adapter);

        return rootView;
      }
    }

Our FragmentPager Adapter

This our FragmentPagerAdapter class.

This class derives from android.support.v4.app.FragmentPagerAdapter.

Here are the responsibilities of this class:

No. Responsibility
1. Receive a android.support.v4.app.FragmentManager via the constructor and pass that FragmentManager to the base FragmentManager class.
2. Define a method getItem() that receives that an integer to act as the position of each fragment. We then instantiate a bundle object and depending on the position put the current page into the bundle, set the bundle as an argument of each fragment, then return the fragment. The return fragment willl then be displayed on the selected tab.
3. Return the total number of actionbar tabs.
    package com.tutorials.viewpagertabsgridview;

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

    public class MyAdapter extends FragmentPagerAdapter {

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

      @Override
      public Fragment getItem(int pos) {
        Bundle info=new Bundle();

        switch (pos) {
        case 0:
          Asia asia=new Asia();
          info.putInt("currentPage", pos++);
          asia.setArguments(info);
          return asia;
        case 1:
          Africa africa=new Africa();
          info.putInt("currentPage", pos++);
          africa.setArguments(info);
          return africa;
        case 2:
          Europe eu=new Europe();
          info.putInt("currentPage", pos++);
          eu.setArguments(info);
          return eu;

        }

        return null;
      }

      @Override
      public int getCount() {
        // TODO Auto-generated method stub
        return 3;
      }

    }

Our MainActivity

This is our main and only activity.

Activities are android components that represent a screen which the user interacts with. If you are interacting with any android app visually then you are using an activity. All those buttons, edittexts, gridviews etc are hosted by an activity.

In fact even the Fragment itself is hosted by an activity.

Here are Functionalities offered by this MainActivity.java file in detail.

No. Responsibility
1. Define a package to host our class. In java classes get grouped into packages. This allows for easier management of these classes and provides a better implementation of Object Oriented Concepts.
2. Add functionalities from other packages using the import statement. We need code libraries that have been wriiten already by other developers. Why? Well this saves us time by us not having to re-invent the wheel everytime by writing tens to hundreds of thousands of lines of code. Also we may not be at the skill level where we would write everything by ourselves. Hence we utilize import to import code written by experienced or even smarter developers.
3. Create our class. This we do using class MainActivity..{} and we then make it public: public class MainActivity..{}. A piblic class can be accessed by other classes even those in different packages.
    package com.tutorials.viewpagertabsgridview;

    import android.app.ActionBar;
    import android.app.ActionBar.Tab;
    import android.app.ActionBar.TabListener;
    import android.app.FragmentTransaction;
    import android.os.Bundle;
    import android.support.v4.app.FragmentActivity;
    import android.support.v4.app.FragmentManager;
    import android.support.v4.view.ViewPager;
    import android.support.v4.view.ViewPager.SimpleOnPageChangeListener;

    public class MainActivity extends FragmentActivity {

      ActionBar ab;
      ViewPager vp;

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

            //ACTIONBAR
            ab=getActionBar();
            ab.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
            ab.setDisplayShowTitleEnabled(true);

            vp=(ViewPager) findViewById(R.id.pager);

            FragmentManager fm=getSupportFragmentManager();

            //CREATE LISTENER
            ViewPager.SimpleOnPageChangeListener listener=new SimpleOnPageChangeListener()
            {
                public void onPageSelected(int position) {

                    ab.setSelectedNavigationItem(position);
                }
                };

                //ASSIGN LISTENER
                vp.setOnPageChangeListener(listener);

                //ADAPTER
                MyAdapter adapter=new MyAdapter(fm);
               vp.setAdapter(adapter);

             //TAB LSITENER
               ActionBar.TabListener tabListener=new TabListener() {

          @Override
          public void onTabUnselected(Tab arg0, FragmentTransaction arg1) {
            // TODO Auto-generated method stub

          }

          @Override
          public void onTabSelected(Tab tab, FragmentTransaction ft) {
            // TODO Auto-generated method stub
            vp.setCurrentItem(tab.getPosition());

          }

          @Override
          public void onTabReselected(Tab arg0, FragmentTransaction arg1) {
            // TODO Auto-generated method stub

          }
        };
         //CRETAE TABS AND SET LISTENER
        Tab t=ab.newTab().setText("ASIA").setIcon(R.drawable.hourglass).setTabListener(tabListener);
        ab.addTab(t);

        t=ab.newTab().setText("Africa").setIcon(R.drawable.reports).setTabListener(tabListener);
        ab.addTab(t);

        t=ab.newTab().setText("Europe").setIcon(R.drawable.selecter).setTabListener(tabListener);
        ab.addTab(t);

        }

    }

Section 4 : Layouts

These are our XML layouts. These layouts will get inflated into Fragments.

(a). ActivityMain.xml

This is our main activity layout.

We add our ViewPager here. Our ViewPager resides in the android.support.v4.view package.

We have to assign it a unique id so that we can reference it from our java code.

It's layout width and height will wrap content in that layout.

    <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"
        android:paddingBottom="@dimen/activity_vertical_margin"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/activity_vertical_margin"
        tools:context=".MainActivity" >

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

    </RelativeLayout>

(b). Asia Layout

This is our Asia Layout. This layout will render Asian countries.

These countries will be shown in a GridView.

We set the number of columns for our GridView using the numColumns attribute : android:numColumns="3".

At the root our XML layout we have a RelativeLayout whose width and height will match parent.

We then define a gridview just below it. We specify the following for our gridview :

  1. Id - To identify the GridView.
  2. Layout Width and Layout Height - To define the rectangular dimensions of our gridview.
  3. We also align it to the Left and Top by setting the layout_alignParentLeft and layout_alignParentTop attributes to true.
  4. The number of columns to render in our gridview.

Here's our code:

    <?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" >

        <GridView
            android:id="@+id/gridView1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentTop="true"
            android:numColumns="3" >
        </GridView>

    </RelativeLayout>

(c). Africa Layout

This is our Africa Layout. This layout will render African countries.

These countries will be shown in a GridView.

We set the number of columns for our GridView using the numColumns attribute : android:numColumns="3".

At the root our XML layout we have a RelativeLayout whose width and height will match parent.

We then define a gridview just below it. We specify the following for our gridview :

  1. Id - To identify the GridView.
  2. Layout Width and Layout Height - To define the rectangular dimensions of our gridview.
  3. We also align it to the Left and Top by setting the layout_alignParentLeft and layout_alignParentTop attributes to true.
  4. The number of columns to render in our gridview.

Here's the code.

    <?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" >

        <GridView
            android:id="@+id/gridView1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:numColumns="3" >
        </GridView>

    </RelativeLayout>

(d). Europe Layout

This is our European Layout. This layout will render European countries.

These countries will be rendered in a GridView.

We set the number of columns for our GridView using the numColumns attribute : android:numColumns="3".

At the root we have a RelativeLayout whose width and height will match parent.

This means that the RelativeLayout's dimensions will match the whole application screen.

We then define a gridview just below it. We specify the following for our gridview :

  1. Id - To identify the GridView.
  2. Layout Width and Layout Height - To define the rectangular dimensions of our gridview.
  3. We also align it to the Left and Top by setting the layout_alignParentLeft and layout_alignParentTop attributes to true.
  4. The number of columns to render in our gridview.

Here's the code.

    <?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" >

        <GridView
            android:id="@+id/gridView1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:layout_alignParentTop="true"
            android:numColumns="3" >
        </GridView>

    </RelativeLayout>

Conclusion

So we have seen how to create a swipeable tabs application containg fragments with gridview. Our GridViews were showing a list of countries from Asia, Europe and Africa. We've made use of ActionBar Tabs. Those Tabs have clickable so users can certainly navigate by clicking them.

On the other hand we've used ViewPager to enable swipeability of our Fragments.

Best Regards,Oclemy.

Comments