Create a Custom Adapter for an Android GridView

GridView Project: 1 2 3 4 5 6 7 8 9

In the previous lesson, we created a string array in an XML file. This array will be used as the sub items in our grid - the heading under the images, in other words. In this lesson, we'll create a Custom Adapter that receives the sub items array. The Custom Adapter also sets the image for each item in the grid. The Adapter is then attached to the GridView, which displays everything for us.

Let's now create the Custom Adapter. This is done in more or less the same way we did previously, for the ListView app - by adding a new class and overriding a View.

To create a new class, right-click your java folder in the Explorer window to the left of Android Studio:

The project file in Android Studio

From the menu that appears, select New > Java Class. You'll then see the following dialogue box appear:

New Java Class dialogue box

Type CustomAdapter for the Name. As the Superclass, type Base. You'll then see a popup menu. This one:

Superclass dropdown list

Select BaseAdapter from the list. Now put a check in the box at the bottom for Show Select Overrides Dialog. Your New Class dialogue box should look like this:

Create New Java Class options

Click OK to see another box appear. This one:

Dialogue box to override methods in Android Studio

On Windows, CTRL click to multiselect the same options as ours, in the image above. On a Mac, COMMAND click to multiselect. So you want to select BaseAdapter, getCount, getItem, getItemId, and getView. Click OK to create your class. Your code should look like this:

Java code showing default methods for a custom adapter

Notice that the CustomAdapter class extends BaseAdapter, which is why we asked you to type BaseAdapter in the superclass area of the first dialogue box. The items you multiselected are methods that are created for you.

Now it's time to add some images to our project.

Open an Explorer window (or Finder, if you're on a Mac), and navigate to where you downloaded the project files. If you haven't yet downloaded the files for this project, get them here:

DOWNLOAD ZIP FILE (24 Kilobytes)

Select all the animal images:

Copying project files

Copy them with CTRL + C (or Command + C on a Mac). Now go back to Android Studio and select the drawable folder:

The drawable folder in Android Studio

Press CTRL + V (or Command + V) to paste the images over. You'll see this dialogue box:

Copying files to the drawable folder

Click OK to complete the copy process. Your drawable folder will then look like this:

Image files copied to the drawable folder in Android Studio

We now need to point to these images with an array in our CustomAdapter code.

Just after the extends BaseAdapter line in your CustomAdapter class, add the following to set up an array:

private Integer[ ] petImages = {

};

(Don't forget the square brackets after Integer. ) In between the curly brackets of the array, type R.drawable. Then type a dot. As soon as you type the dot, you should see a popup list with all your drawable images:

Drawable imahe popup list

Select a drawable from the list, and then type a comma. Here's what you code should look like:

Java code setting up an Integer array

Notice that a thumbnail of the image appears in the margins.

Hit the enter key on your keyboard to give yourself a new line. Now add the rest of the drawables:

R.drawable.dog,
R.drawable.fish,
R.drawable.horse,
R.drawable.rabbit,
R.drawable.parrot,
R.drawable.pigeon,
R.drawable.duck

The final drawable doesn't need a comma after it. Here's what the coding window will look like:

Android Studio showing an Integer array

(Incidentally, if you're wondering why the images have to go in an Integer array rather than a String array, it's because Android turns an image into an ID when you put it in the drawable folder. The ID is an Integer.)

We need three variables at the top of the code. These ones:

private String[ ] imageLabels;
private Context context;
private LayoutInflater thisInflater;

(ALT + ENTER for any red text, or add import android.view.LayoutInflater; to the top of your code.)

We're going to be passing our CustomAdapter an array of headings. They will go into a new array which we've called imageLabels

The Context variable just ensures that we know which of our app's screens we're talking about. The LayoutInflater is used to inflate the XML file we create for a row item.

Now locate the CustomAdapter constructor in your code:

public CustomAdapter( ) {

super();

}

You can delete the super line. In between the round brackets of CustomAdapter, pass in a Context object and a String array:

public CustomAdapter( Context con, String[ ] labs ) {

}

You might need to press ALT + ENTER on any red text, or add import android.content.Context; to the top of your code.

In between the curly brackets of the constructor, set some values for the variables at the top of your code:

this.context = con;
this.thisInflater = LayoutInflater.from(con);
this.imageLabels = labs;

The top half of your code should look like this:

Java code setting up a custom adapter for an Android GridView

So the con variable gets handed to the Context object we set up. The LayoutInflator has a from method we can use. In between the round brackets of from you need a context, which is con for us. The labs array is stored in the imageLabels array at the top of the code.

Let's fill out the getCount, getItem and getItemId methods. There's only one line for each.

The count we want is how many items are in the petImages array. Add this line to getCount:

@Override
public int getCount() {

return petImages.length;

}

For getItem and getItemId we only need the position. Update your two methods like this:

@Override
public Object getItem(int position) {

return position;

}

@Override
public long getItemId(int position) {

return position;

}

Your three methods should look like this:

Overriding methods in Java

The only thing left to do now, in the CustomAdapter, is write code for the getView method.

Add this IF Statement between the curly brackets of getView;

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

if (convertView == null) {

}

}

The variable convertView is a View object. We'll be setting our image and heading XML file as convertView. But we need to check if it's null or not. If it's null then we can go ahead and set some values. If you don't check for null then you'd get too many image and headings being created, and the app could crash. We only want to create an image and heading View if convertView is null.

Add this between the curly brackets of the IF Statement:

convertView = thisInflater.inflate( R.layout.grid_item, parent, false );

Our XML file with the ImageView and TextView was called grid_item. We're inflating this to create a View object. This then goes into the variable called convertView. (We did all this in a previous tutorial on ListViews, so we won't explain the other parameters here.)

Now we have a reference to our XML file, add these two lines:

TextView textHeading = (TextView) convertView.findViewById(R.id.petHeading);
ImageView thumbnailImage = (ImageView) convertView.findViewById(R.id.petImage);

You may need to press ALT + ENTER to add the imports for ImageView and TextView. Or add these two lines to the top of your code:

import android.widget.ImageView;
import android.widget.TextView;

All the new lines do, though, is get references to the petHeading and petImage widgets from our grid_item XML file. We're setting up a TextView variable called textHeading, and a ImageView variable called thumbnailImage.

To store something in these two variables, add the following lines:

textHeading.setText( imageLabels[position] );
thumbnailImage.setImageResource( petImages[position] );

Two understand these lines, remember that imageLabels and petImages are both arrays. In between the square brackets of the arrays, we have the position variable from the round brackets of getView. Whichever label or image is at a particular position in the array gets its text or image resource set.

Finally, outside of the IF Statement, we can return convertView:

Java code for a getView method

And here's the whole of the code for your CustomAdapter:

Custom Adapter for an Android GridView

We're done with the CustomAdapter class. Let's go back to MainActivity.java and test it out.