Create a new project in Android Studio called Image Pager
. Use the Basic Activity template and leave the remainder of the settings at their defaults.
The images are located in the download bundle in the Chapter 25/Image Pager/drawable
folder. The following diagram shows them in Windows Explorer:
Add the images to the drawable
folder in the project explorer or, of course, you could add more interesting images, perhaps some photos you have taken.
For a simple image paging app, we use the PagerAdapter
class. We can think of this as being like RecyclerApater
, but for images, as it will handle the display of an array of images in a ViewPager
widget. This is much like how RecyclerAdapter
handles the display of the content of an ArrayList
in a ListView
. All we need to do is override the appropriate methods.
To implement an image gallery with PagerAdapter
, we first need a ViewPager
in our main layout. So you can see precisely what is required here is the actual XML code for activity_main.xml
. Edit layout_main.xml
to look exactly like this:
<RelativeLayout xmlns:android= "http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" > <androidx.viewpager.widget.ViewPager android:id="@+id/pager" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </RelativeLayout>
The slightly unusually named class, androidx.ViewPager.widget.ViewPager,
is the class that makes this functionality available in Android versions that were released prior to ViewPager
.
Next, a bit like we needed a layout to represent a list item, we need a layout to represent an item, in this case an image, in our ViewPager
. Create a new layout file in the usual way, and call it pager_item.xml
. It will have a single ImageView
with an id of imageView
.
Use the visual designer to achieve this or copy the following XML into pager_item.xml
:
<RelativeLayout xmlns:android= "http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" > <androidx.viewpager.widget.ViewPager android:id="@+id/pager" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </RelativeLayout>
Now we can make a start on our PagerAdapter
.
Next, we need to extend PagerAdapter
to handle images. Create a new class called ImagePagerAdapter
and make it extend PagerAdapter
.
Add the following imports to the top of the ImagePagerAdapter
class. We normally rely on using the shortcut Alt + Enter to add imports. We are doing things slightly differently this time because there are some very similarly named classes that will not suit our objectives.
Add the following imports to the ImagePagerAdapter
class:
import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.RelativeLayout; import androidx.viewpager.widget.PagerAdapter; import androidx.viewpager.widget.ViewPager;
Here is the class declaration with the extends...
code added, as well as a couple of member variables. These variables are a Context
object that we will use shortly and an int
array called images
. The reason for having an int
array for images is because we will store int
identifiers for images. We will see how this works in a few code blocks time. The last member variable is a LayoutInflater,
which you can probably guess will be used to inflate each of the instances of pager_item.xml
.
Extend PagerAdapter
and add the member variables we have just discussed:
public class ImagePagerAdapter extends PagerAdapter { Context context; int[] images; LayoutInflater inflater; }
Now we need a constructor that sets up ImagerPagerAdapter
by receiving the Context
from MainActivity,
as well as the int
array for the images, and initializing the member variables with them.
Add the highlighted constructor method to the ImagePagerAdapter
class;
public ImagePagerAdapter( Context context, int[] images) { this.context = context; this.images = images; }
Now, we must override the required methods of PagerAdapter
. Immediately after the previous code, add the overridden getCount
method, which simply returns the number of image IDs in the array. This method is used internally by the class:
@Override public int getCount() { return images.length; }
Now we must override the isViewFromObject
method that just returns a Boolean,
dependent upon whether the current View
is the same or associated with the current Object
as passed in as a parameter. Again, this is a method that is used internally by the class. Immediately after the previous code, add this overridden method:
@Override public boolean isViewFromObject(View view, Object object) { return view == object; }
Now we must override the instantiateItem
method and this is where we do most of the work that concerns us. First, we declare a new ImageView
object, and then we initialize our LayoutInflater
member. Next, we use the LayoutInflater
to declare and initialize a new View
from our pager_item.xml
layout file.
After this, we get a reference to the ImageView
inside the pager_item.xml
layout. We can now add the appropriate image as the content of the ImageView
based on the position parameter of the instantiateItem
method and the appropriate ID from the images
array.
Finally, we add the layout to the PagerAdapter
with addView
and return from the method.
Now add the method we have just discussed:
@Override public Object instantiateItem( ViewGroup container, int position) { ImageView image; Inflater = (LayoutInflater) context.getSystemService( Context.LAYOUT_INFLATER_SERVICE); View itemView = inflater.inflate( R.layout.pager_item, container,false); // get reference to imageView in pager_item layout image = (ImageView) itemView.findViewById(R.id.imageView); // Set an image to the ImageView image.setImageResource(images[position]); // Add pager_item layout as the current page to the ViewPager ((ViewPager) container).addView(itemView); return itemView; }
The last method we must override is destroyItem,
which the class can call when it needs to remove an appropriate item based on the value of the position
parameter.
Add the destroyItem
method after the previous code and before the closing curly brace of the ImagePagerAdapter
class:
@Override public void destroyItem(ViewGroup container, int position, Object object) { // Remove pager_item layout from ViewPager ((ViewPager) container) .removeView((RelativeLayout) object); }
As we saw when coding ImagePagerAdapter,
there is very little to it. It is just a case of properly implementing the overridden methods that the ImagePagerAdapter
class uses to help make things work smoothly behind the scenes.
Now we can code the MainActivity
class that will use the ImagePagerAdapter
.
Finally, we can code our MainActivity
class. As with the ImagePagerAdapter
class, for clarity, add the following import statements manually to the MainActivity.java
class before the class declaration as shown in the following snippet:
import androidx.appcompat.app.AppCompatActivity; import androidx.viewpager.widget.PagerAdapter; import androidx.viewpager.widget.ViewPager;
We need a few member variables. Unsurprisingly, we need a ViewPager,
which will be used to get a reference to the ViewPager
in our layout, as well as an ImagePagerAdapter
reference for the class we have just coded. We also need an int
array to hold an array of image ids.
Adapt the MainActivity
class to be as follows:
public class MainActivity extends AppCompatActivity { ViewPager viewPager; PagerAdapter adapter; int[] images; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ...
All the rest of the code goes in onCreate
. We initialize our int
array with each of the images that we added to the drawable-xhdpi
folder.
We initialize the ViewPager
in the usual way with the findViewByID
method. We also initialize our ImagePagerAdapter
by passing in a reference of MainActivity
and the images
array, as required by the constructor that we coded previously. Finally, we bind the adapter to the pager with setAdapter
.
Code onCreate
to look just like this following code:
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Grab all the images and stuff them in our array images = new int[] { R.drawable.image1, R.drawable.image2, R.drawable.image3, R.drawable.image4, R.drawable.image5, R.drawable.image6 }; // get a reference to the ViewPager in the layout viewPager = (ViewPager) findViewById(R.id.pager); // Initialize our adapter adapter = new ImagePagerAdapter(MainActivity.this, images); // Binds the Adapter to the ViewPager viewPager.setAdapter(adapter); }
Here we can see the first image from our int
array:
Swipe a little right and left to see the pleasing manner in which the images transition smoothly:
Now we will build an app with almost identical functionality, except that each page in the pager will be a Fragment,
which could have any or all of the functionality a regular Fragment
can have because they are regular Fragments
.
18.191.223.123