Thumbnail View of a Large Number of Photos with Three20
Three20 is an open-source library for iOS applications. It provides many handy features that make your iOS development life much easier. It’s used in many popular iOS apps, including Facebook. One of the features that I’d like to discuss is the photo thumbnail view. Here’s a screenshot of TTCatalog app, a sample app that comes with Three20 project.
There are many blogs that talk about how to use Three20 for displaying thumbnail view. I’m not going to repeat it here. Instead, I’ll talk about how you can display a large number of thumbnails with “load more” at the bottom of the list. This kind of “paging” is commonly found in apps that have to deal with a large data set. For instance, the Mail app loads 50 messages at a time. A “Load More Messages…” will appear at the bottom of the list and if tapped, the app will load additional 50.
The main view controller of this component is called TTThumbsViewController. Typically you’d subclass this class to add more customizations. This controller depends on a model that is derived from TTModel class and a class that implements TTPhotoSource protocol. Each thumbnail is of class that implements TTPhoto.
I’ve created a simple app for this article. Its main purpose is to display photos of a Facebook album. Here are the three main classes:
@interface MyFacebookPhotosViewController : TTThumbsViewController <TTThumbsViewControllerDelegate> @interface FacebookPhotoSource : TTModel <TTPhotoSource, FBRequestDelegate> @interface FacebookPhoto : NSObject <TTPhoto>
TTThumbsViewController has all the logic to display “Load more” cell at the bottom of the list. It’s up to the data source to “tell” the controller if there are more data to load. So, most of our works will be in FacebookPhotoSource class.
Two important methods in TTPhotoSource that tell TTThumbsViewController if “load more” needs to be present:
- (NSInteger)numberOfPhotos { return 100; }
- (NSInteger)maxPhotoIndex { return _photos.count-1; }
numberOfPhotos tells the controller the total number of thumbnails in the data set. maxPhotoIndex tells the number of thumbnails that are currently displayed. So, as long as numberOfPhotos > maxPhotoIndex, the “load more…” cell will appear.
In this example, I hardcoded numberOfPhotos to return 100. I could’ve called a Facebook Graph API to retrieve the number of photos in an album and used that count as the return value. But that would make the sample app more complex and harder to follow. It’s definitely not the intention of this discussion.
Let’s take a look at another important function:
- (void)load:(TTURLRequestCachePolicy)cachePolicy more:(BOOL)more {
_loadState = loading;
// increment page count if loading more...
if (more) _page++;
NSString *request = [NSString stringWithFormat:@"10150146071791729/photos?limit=%d&offset=%d", NUM_PHOTOS_PER_PAGE, _page*NUM_PHOTOS_PER_PAGE];
[_facebook requestWithGraphPath:request andDelegate:self];
}
“more” argument will be YES if the controller is trying to load data when user tapped on “load more…” cell. We keep a page counter (_page) and use it to construct a query to Facebook. Here, I hardcoded another constant: album id (10150146071791729). The Facebook Graph API to obtain list of photos in an album is https://graph.facebook.com/{album_id}/photos. It also accepts limit and offset as additional arguments.
NUM_PHOTOS_PER_PAGE is defined as 24. Obviously, it can be any arbitrary number. But I picked 24 because it’s exactly divisible by 4 (number of thumbs in portrait mode) and 6 (in landscape). That way, you won’t have blank columns at the last row.
Here’s how the sample app looks like:
When “Load More Photos…” cell is tapped:
You can download this sample app here. Enjoy.