Sunday, July 8, 2012

iPhone JSON Flickr Tutorial – Part 3

In this tutorial we wrap up by adding a simple image viewer that will display a larger variation of the image when the user taps on a row in the table. We’ll add some code to slide the larger images on/off screen, which is a nice visual effect for this application. You can review the finished application by watching the video below:


Download iPhone JSON Xcode Project
You can download the Xcode project and walk through the source code:
  1. Download iPhone, JSON and Flickr – Part 3 Xcode project
Zoomed Image Viewer
Let’s begin by creating a simple class for viewing the larger variation of the image in the table. The class definition follows:
@interface ZoomedImageView : UIView
{
UIImageView *fullsizeImage;
}
 
- (id)initWithURL:(NSURL *)url;
 
@end
Not much here – just a UIView with an UIImageView to hold the large image downloaded from Flickr. Let’s look at the implementation of this class.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#import "ZoomedImageView.h"
 
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Private interface definitions
*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

@interface ZoomedImageView(private)
- (void)slideViewOffScreen;
@end
 
@implementation ZoomedImageView
 
/**************************************************************************
*
* Private implementation section
*
**************************************************************************/

 
#pragma mark -
#pragma mark Private Methods
 
- (void)slideViewOffScreen
{
// Get the frame of this view
CGRect frame = self.frame;
 
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:.45];
 
// Set view to this offscreen location
frame.origin.x = -320;
self.frame = frame;
 
// Slide view
[UIView commitAnimations];
}
 
/**************************************************************************
*
* Class implementation section
*
**************************************************************************/

 
#pragma mark -
#pragma mark Initialization
 
- (id)initWithURL:(NSURL *)url
{
if (self = [super init])
{
// Create the view offscreen (to the right)
self.frame = CGRectMake(320, 0, 320, 240);
 
// Setup image
NSData *imageData = [NSData dataWithContentsOfURL:url];
fullsizeImage = [[UIImageView alloc] initWithImage:[UIImage imageWithData:imageData]];
 
// Center the image...
int width = fullsizeImage.frame.size.width;
int height = fullsizeImage.frame.size.height;
 
int x = (320 - width) / 2;
int y = (240 - height) / 2;
 
[fullsizeImage setFrame:CGRectMake(x, y, width, height)];
fullsizeImage.userInteractionEnabled = YES;
[self addSubview:fullsizeImage];
 
}
 
return self;
}
 
#pragma mark -
#pragma mark Event Mgmt
 
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[self slideViewOffScreen];
 
// We now send the same event up to the next responder
// (the JSONFlickrViewController) so we can show enable
// the search textfield again
[self.nextResponder touchesBegan:touches withEvent:event];
 
}
 
#pragma mark -
#pragma mark Cleanup
 
- (void)dealloc
{
[fullsizeImage release];
[super dealloc];
}
 
@end
It starts the the initialization code on line 46 – we pass in the URL of the larger image that we saved previously when making the original request for images matching a search string (more on that below).
Notice the x coordinate on line 51 has a value of 320, which sets this view off-screen to the right. As we’ll see momentarily, to accomplish the slide-in effect we’ll move the x coordinate to an on-screen location, which will slide the image into place. We wrap up the initialization code by creating the image, centering the image in the view, and adding the image as a subview.
Once an image is shown on screen, when a new image is requested by the user (tapping on a table row) we need to slide the current view off the screen to the left. The code beginning on line 21 shows how we accomplish this – setup the animation, move the frame for the current image off-screen to the left (-320) and commit the animation.
Search TextField and Activity Indicator
Our next task is to create the search textfield. Head over to the JSONFlickrViewControllerimplementation file, where we need to add a UITextField, also add an activity indicator as shown here:
@interface JSONFlickrViewController : UIViewController <UITableViewDelegate, UITableViewDataSource, UITextFieldDelegate>
{
UITextField *searchTextField;
UITableView *theTableView;
NSMutableArray *photoTitles; // Titles of images
NSMutableArray *photoSmallImageData; // Image data (thumbnail)
NSMutableArray *photoURLsLargeImage; // URL to larger image
 
ZoomedImageView *fullImageViewController;
UIActivityIndicatorView *activityIndicator;
}
The code for initializing the textfield and activity indicator are inside the init method of theJSONFlickrViewController class:
- (id)init
 
...
 
// Create textfield for the search text
searchTextField = [[[UITextField alloc] initWithFrame:CGRectMake(110, 100, 100, 40)] retain];
[searchTextField setBorderStyle:UITextBorderStyleRoundedRect];
searchTextField.placeholder = @"search";
searchTextField.returnKeyType = UIReturnKeyDone;
searchTextField.clearButtonMode = UITextFieldViewModeWhileEditing;
searchTextField.delegate = self;
[self.view addSubview:searchTextField];
[searchTextField release];
 
// Create activity indicator
activityIndicator = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(220, 110, 15, 15)];
activityIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyleWhite;
activityIndicator.autoresizingMask = (UIViewAutoresizingFlexibleLeftMargin |
UIViewAutoresizingFlexibleRightMargin |
UIViewAutoresizingFlexibleTopMargin |
UIViewAutoresizingFlexibleBottomMargin);
[ activityIndicator sizeToFit];
activityIndicator.hidesWhenStopped = YES;
[self.view addSubview:activityIndicator];
 
...
}
When new search text is entered, the code in the method textFieldShouldReturn will be run. Inside this method we remove all the objects from each of the arrays we created previously when calling Flickr (if we’ve called Flickr previously) and start the activity indicator.
Next, call the method searchFlickrPhotos which will kick-off the process for calling the Flickr API and rebuilding the arrays of content based on the JSON returned from the service – See Part 1 for more information. Once the query is complete, the activity indicator will be stopped (you can see this code in the downloaded Xcode project).
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
 
// Remove any content from a previous search
[photoTitles removeAllObjects];
[photoSmallImageData removeAllObjects];
[photoURLsLargeImage removeAllObjects];
 
// Begin the call to Flickr
[self searchFlickrPhotos:searchTextField.text];
 
// Start the busy indicator
[activityIndicator startAnimating];
 
return YES;
}
Wrapping all the Pieces Together
At this point all that’s left is to recognize when a new table row has been selected and begin the process for downloading the larger image view and sliding the image into place on the display. It all begins in the code for managing the table with the method shown below:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 
{
searchTextField.hidden = YES;
 
// If we've created this VC before...
if (fullImageViewController != nil)
{
// Slide this view off screen
CGRect frame = fullImageViewController.frame;
 
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:.45];
 
// Off screen location
frame.origin.x = -320;
fullImageViewController.frame = frame;
 
[UIView commitAnimations];
}
 
[self performSelector:@selector(showZoomedImage:) withObject:indexPath afterDelay:0.1];
}
We begin by hiding the search textfield, then, if a zoomed image is visible, we need to slide it off-screen – we do this by setting up the animation, move the image location (frame) to an off-screen location (-320) and committing the animation. Once that is complete, we callshowZoomedImage to display the image the user requested.
The last chunk of code is for displaying the requested image:
- (void)showZoomedImage:(NSIndexPath *)indexPath
{
// Remove from view (and release)
if ([fullImageViewController superview])
[fullImageViewController removeFromSuperview];
 
fullImageViewController = [[ZoomedImageView alloc] initWithURL:[photoURLsLargeImage objectAtIndex:indexPath.row]];
 
[self.view addSubview:fullImageViewController];
 
// Slide this view off screen
CGRect frame = fullImageViewController.frame;
 
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:.45];
 
// Slide the image to its new location (onscreen)
frame.origin.x = 0;
fullImageViewController.frame = frame;
 
[UIView commitAnimations];
}
We start by releasing the current zoomed view (if there is one). Next, we create a newZoomedImageView, passing in the URL of the larger image that was saved previously when we parsed the JSON data (see the previous posts). We setup the animation, move x coordinate of the image into place and commit the animation.
Final Notes
With that, we have a complete working application that will call Flickr based on a user requested search string, display a table of images and titles and allow zooming in on each image by selecting a row in the table.
It’s hard to get the big picture when looking at code snippets as shown in this tutorial. Once you download and tinker with the Xcode project, it’ll all make sense.

No comments:

Post a Comment