For this project I am going to use online images so that their URLs can be passed to the app from a JSON stream with some additional data. This JSON stream is then parsed using GSON into a Gallery model object that contains an ArrayList of Image objects. Each Image object contains a caption for the image, the URL for the higher resolution version of the image, and a thumbnail for the image. The thumbnails are displayed in a GridView, and the higher resolution images with captions are displayed in a separate activity with a ViewPager. The final product with very little styling (mind you, if this were to be a production app then more styling would be a necessity) will look like this:
As can be seen in the first image, the main activity is simply a grid of images. Instead of using a standard ImageView, I have a SquareImageView class that takes the images and displays them in a square in order to keep the rows uniform. This is done by calling setMeasuredDimension to make the image height equal the width when the view calls onMeasure
SquareImageView.java
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int dimension = getDefaultSize( getSuggestedMinimumWidth(), widthMeasureSpec );
setMeasuredDimension(dimension, dimension);
}
The feed is pulled down in MainActivity using Volley and GSON to put the JSON data into the model objects:
MainActivity.java
private void loadFeed() {
String feedUrl = getString( R.string.feed_url );
GsonRequest<Gallery> request = new GsonRequest<Gallery>( Request.Method.GET,
feedUrl, Gallery.class, successListener(), errorListener() );
Volley.newRequestQueue( getApplicationContext() ).add( request );
}
public Response.Listener successListener()
{
return new Response.Listener<Gallery>()
{
@Override
public void onResponse( Gallery gallery ) {
mGallery.setImages( gallery.getImages() );
mGallery.setDescription( gallery.getDescription() );
setupUI();
}
};
}
setupUI() adds all of the images from the gallery into an ArrayAdapter for the GridView, and adds a click listener to open an activity for viewing the full resolution images. The adapter for the grid uses the viewholder pattern and the Picasso library to load the thumbnail images into the grid, as can be seen in GalleryGridAdapter.java. When an image is clicked in the grid, all images are passed to the next activity as well as the clicked position, allowing the ImageDetailsActivity to display the ViewPager at the correct location
MainActivity.java
mGridView.setOnItemClickListener( new AdapterView.OnItemClickListener()
{
@Override
public void onItemClick(AdapterView<?> adapterView,
View view, int position, long id) {
Intent intent = new Intent( getApplicationContext(), ImageActivity.class );
intent.putExtra( ImageActivity.EXTRA_IMAGE_LIST,
(ArrayList) mGallery.getImages() );
intent.putExtra( ImageActivity.EXTRA_CUR_IMAGE, position );
startActivity( intent );
}
ImageDetailsActivity.java
if( getIntent() == null || getIntent().getExtras() == null )
return;
List<Image> tmpList = getIntent().getExtras()
.getParcelableArrayList( EXTRA_IMAGE_LIST );
mCurrentImagePosition = getIntent().getExtras().getInt( EXTRA_CUR_IMAGE, 0 );
mAdapter = new ImageStateViewPager( getSupportFragmentManager(), tmpList );
ImageActivity takes the images and loads them into a FragmentStatePagerAdapter which returns a new instance of ImageDetailsFragment with passed Image object from getItem.
ImageStateViewPager.java
@Override
public Fragment getItem( int position ) {
return( position < 0 || position > ( mImageList.size() - 1 ) ) ? null :
ImageFragment.newInstance( mImageList.get( position ) );
}
This fragment displays a progress spinner until Picasso has loaded the external image, and displays a caption that can have visibility toggled by tapping on the image. By using a ViewPager, the user is able to swipe left or right to view additional images while only keeping a max of three images in memory at a time.
And with that, we have a simple gallery component for Android. There's a lot of modifications that can be made to this, such as adding progress spinners for the grid as the initial feed is loaded, and spinners for each image object as Picasso loads them into the grid, as well as styles to show overlays and change spacing in the grid. Overall the gallery is a useful component for displaying graphical content to your users, and makes a great addition to any Android developer's arsenal of UI components.