Thursday 25 July 2013

GridView with ViewPager like Android Menu


Hi everyone there, this is my first attempt to write a blog, bare with me for any mistakes. A few days back I had this requirement of creating a Grid view which will be able to slide and also indicate how many screens the grid view has in total, just like we do in the Menu option of any Android phone. So after lot of research I made a solution with the help of an library which will be helpful to show the number of pages just like we get in menu option of android phone and so thought of putting it up on my blog so that others would be benefited from it.

Firstly I would like you to thank Jake Wharton for his library "Android-ViewPagerIndicator" which can be downloaded from here https://github.com/JakeWharton/Android-ViewPagerIndicator

We need to download and import it in our project work space. I hope you guys wont be having much of trouble doing that. Firstly i would like to show how the output will look like. Please see it in full screen where you will see the total number of dots equal to total number of pages at the bottom.




The next step is start writing our code for the actual project. So lets first start with the XML files required. Total we will need 3 layout files.

1) activity_main.xml : - which holds the viewpager and also the PagerIndicator.
2) grid.xml: - which holds the gridview
3) custom.xml - which holds the gridview custom layout (A gridview with a Image and text in our case).

The activity_main.xml looks like this:

<LinearLayout 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:background="@android:color/black"
      android:orientation="vertical"
      tools:context=".MainActivity" >

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

      <com.viewpagerindicator.CirclePageIndicator
           android:id="@+id/pagerIndicator"
           android:layout_width="fill_parent"
           android:layout_height="wrap_content"
           android:layout_marginBottom="5dp"
           android:layout_marginTop="5dp"
           android:padding="3dp" />
</LinearLayout>

It holds a LinearLayout which will hold our GridView a ViewPager and a PagerIndicator. The grid.xml looks like this:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      android:orientation="vertical" >

     <GridView
          android:id="@+id/gridView"
          android:layout_width="fill_parent"
          android:layout_height="wrap_content"
          android:layout_margin="1dp"
          android:layout_marginTop="2dp"
          android:horizontalSpacing="2dp"
          android:listSelector="@android:color/transparent"
          android:numColumns="3"
          android:stretchMode="columnWidth"
          android:verticalSpacing="2dp" />
</LinearLayout>

It has a GridView with 3 columns. You can specify as much as you want. The last xml file is the custom.xml which holds a ImageView and TextView for every grid item. The custom.xml looks like this:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:orientation="vertical"
      android:padding="5dp" >

      <ImageView
           android:id="@+id/grid_item_image"
           android:layout_width="50dp"
           android:layout_height="50dp"
           android:layout_marginRight="10dp"
           android:src="@drawable/ic_launcher" >
      </ImageView>

      <TextView
           android:id="@+id/grid_item_label"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:layout_marginTop="5dp"
           android:textColor="@android:color/white"
           android:textSize="15sp" >
      </TextView>
</LinearLayout>

The following are the class files we require. The first file is the MainActivity.class file which looks like below:

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

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.Log;

import com.viewpagerindicator.PagerIndicator;

public class MainActivity extends FragmentActivity {

 public PagerIndicator mIndicator;
 private ViewPager awesomePager;
 private PagerAdapter pm;

 ArrayList codeCategory;

 String deviceNames[] = { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J",
   "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W",
   "X", "Y", "Z" };

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

  awesomePager = (ViewPager) findViewById(R.id.pager);
  mIndicator = (PagerIndicator) findViewById(R.id.pagerIndicator);

  ArrayList a = new ArrayList();

  Category m = new Category();
  for (int i = 0; i < deviceNames.length; i++) {
   a.add(i, deviceNames[i]);
   m.name = a.get(i);
  }

  codeCategory = new ArrayList();
  codeCategory.add(m);

  Iterator it = a.iterator();

  List gridFragments = new ArrayList();
  it = a.iterator();

  int i = 0;
  while (it.hasNext()) {
   ArrayList itmLst = new ArrayList();

   GridItems itm = new GridItems(0, it.next());
   itmLst.add(itm);
   i = i + 1;

   if (it.hasNext()) {
    GridItems itm1 = new GridItems(1, it.next());
    itmLst.add(itm1);
    i = i + 1;
   }

   if (it.hasNext()) {
    GridItems itm2 = new GridItems(2, it.next());
    itmLst.add(itm2);
    i = i + 1;
   }

   if (it.hasNext()) {
    GridItems itm3 = new GridItems(3, it.next());
    itmLst.add(itm3);
    i = i + 1;
   }

   if (it.hasNext()) {
    GridItems itm4 = new GridItems(4, it.next());
    itmLst.add(itm4);
    i = i + 1;
   }

   if (it.hasNext()) {
    GridItems itm5 = new GridItems(5, it.next());
    itmLst.add(itm5);
    i = i + 1;
   }

   if (it.hasNext()) {
    GridItems itm6 = new GridItems(6, it.next());
    itmLst.add(itm6);
    i = i + 1;
   }

   if (it.hasNext()) {
    GridItems itm7 = new GridItems(7, it.next());
    itmLst.add(itm7);
    i = i + 1;
   }

   if (it.hasNext()) {
    GridItems itm8 = new GridItems(8, it.next());
    itmLst.add(itm8);
    i = i + 1;
   }

   GridItems[] gp = {};
   GridItems[] gridPage = itmLst.toArray(gp);
   gridFragments.add(new GridFragment(gridPage, MainActivity.this));
  }

  pm = new PagerAdapter(getSupportFragmentManager(), gridFragments);
  awesomePager.setAdapter(pm);
  mIndicator.setViewPager(awesomePager);

 }

 private class PagerAdapter extends FragmentStatePagerAdapter {
  private List fragments;

  public PagerAdapter(FragmentManager fm, List fragments) {
   super(fm);
   this.fragments = fragments;
  }

  @Override
  public Fragment getItem(int position) {
   return this.fragments.get(position);
  }

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

As you can see we have to create objects of PagerIndicator, ViewPager & PagerAdapter.
The PagerIndicator to indicate the current page
The ViewPager is just another view like any other view. We will set the PagerAdapter to it.

Another important class is GridFragment class which will add our gridview to our layout. It looks as shown below:

import android.annotation.SuppressLint;
import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.Toast;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.GridView;

@SuppressLint("ValidFragment")
public class GridFragment extends Fragment {

 private GridView mGridView;
 private GridAdapter mGridAdapter;
 GridItems[] gridItems = {};
 private Activity activity;

 public GridFragment(GridItems[] gridItems, Activity activity) {
  this.gridItems = gridItems;
  this.activity = activity;
 }

 @Override
 public View onCreateView(LayoutInflater inflater, ViewGroup container,
   Bundle savedInstanceState) {
  View view;
  view = inflater.inflate(R.layout.grid, container, false);
  mGridView = (GridView) view.findViewById(R.id.gridView);
  return view;
 }

 @Override
 public void onActivityCreated(Bundle savedInstanceState) {
  super.onActivityCreated(savedInstanceState);

  if (activity != null) {

   mGridAdapter = new GridAdapter(activity, gridItems);
   if (mGridView != null) {
    mGridView.setAdapter(mGridAdapter);
   }

   mGridView.setOnItemClickListener(new OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView parent, View view,
      int position, long id) {
     onGridItemClick((GridView) parent, view, position, id);
    }
   });
  }
 }

 public void onGridItemClick(GridView g, View v, int position, long id) {
  Toast.makeText(
    activity,
    "Position Clicked: - " + position + " & " + "Text is: - "
      + gridItems[position].title, Toast.LENGTH_LONG).show();
  Log.e("TAG", "POSITION CLICKED " + position);
 }
}

Here we have inflated our grid.xml and set adapter to the gridview. Also to check which item in the gridview was clicked we have used the setOnItemClickListener method. Next is the GridAdapter class to set the adapter to GridView. It looks as shown below:

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;

public class GridAdapter extends BaseAdapter {

 Context context;
 int images[] = { R.drawable.ic_launcher, R.drawable.ios,
   R.drawable.windows, R.drawable.ic_launcher, R.drawable.ios,
   R.drawable.windows, R.drawable.ic_launcher, R.drawable.ios,
   R.drawable.windows };

 public class ViewHolder {
  public ImageView imageView;
  public TextView textTitle;
 }

 private GridItems[] items;
 private LayoutInflater mInflater;

 public GridAdapter(Context context, GridItems[] locations) {

  mInflater = (LayoutInflater) context
    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
  this.context = context;
  items = locations;

 }

 public GridItems[] getItems() {
  return items;
 }

 public void setItems(GridItems[] items) {
  this.items = items;
 }

 @Override
 public int getCount() {
  if (items != null) {
   return items.length;
  }
  return 0;
 }

 @Override
 public void notifyDataSetChanged() {
  super.notifyDataSetChanged();
 }

 @Override
 public Object getItem(int position) {
  if (items != null && position >= 0 && position < getCount()) {
   return items[position];
  }
  return null;
 }

 @Override
 public long getItemId(int position) {
  if (items != null && position >= 0 && position < getCount()) {
   return items[position].id;
  }
  return 0;
 }

 public void setItemsList(GridItems[] locations) {
  this.items = locations;
 }

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

  View view = convertView;
  ViewHolder viewHolder;

  if (view == null) {

   view = mInflater.inflate(R.layout.custom, parent, false);
   viewHolder = new ViewHolder();
   viewHolder.imageView = (ImageView) view
     .findViewById(R.id.grid_item_image);
   viewHolder.textTitle = (TextView) view
     .findViewById(R.id.grid_item_label);
   view.setTag(viewHolder);
  } else {
   viewHolder = (ViewHolder) view.getTag();
  }

  GridItems gridItems = items[position];
  setCatImage(position, viewHolder, gridItems.title);
  return view;
 }

 private void setCatImage(int pos, ViewHolder viewHolder, String catTitle) {
  viewHolder.imageView.setImageResource(images[pos]);
  viewHolder.textTitle.setText(catTitle);
 }
} 
Below are the other GetterSetter classes. First is the GridItems.class
public class GridItems {

 public int id;
 public String title;

 public GridItems(int id, String address) {
  this.id = id;
  this.title = address;
 }
}

The next is the Category.class

public class Category {
 int id;
 String name;

 public Category(int id, String name) {
  this.id = id;
  this.name = name;
 }

 public Category() {
 }

 public int getId() {
  return id;
 }

 public void setId(int id) {
  this.id = id;
 }

 public String getName() {
  return name;
 }

 public void setName(String name) {
  this.name = name;
 }
}