Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Beginning iOS5 Development.pdf
Скачиваний:
7
Добавлен:
09.05.2015
Размер:
15.6 Mб
Скачать

CHAPTER 20: The Camera and Photo Library

677

Road Testing the Camera and Library

In this chapter, we’re going to build an application that lets the user take a picture or shoot some video with the camera, or select one from the photo library, and then display the selection on the screen (see Figure 20–2). If the user is on a device without a camera, we will hide the New Photo or Video button and allow only selection from the photo library.

Figure 20–2. The Camera application in action

Create a new project in Xcode using the Single View Application template, naming the application Camera. Before working on the code itself, we need to add a couple of frameworks that our application will use. Using the techniques you’ve used in previous chapters, add the MediaPlayer and MobileCoreServices frameworks.

We’ll add a couple of outlets in this application’s view controller. We need one to point to the image view so that we can update it with the image returned from the image picker. We’ll also need an outlet to point to the New Photo or Video button so we can hide the button if the device doesn’t have a camera.

Since we’re going to allow users to decide whether to grab a video or an image, we’ll use the MPMoviePlayerController class to display the chosen video, so we need a property for that. Two more properties keep track of the last selected image and video,

www.it-ebooks.info

678

CHAPTER 20: The Camera and Photo Library

along with a string to determine whether a video or image was the last thing chosen. Finally, we’ll keep track of the size of the image view, for resizing the captured image to match our display size.

We also need two action methods: one for the New Photo or Video button and one for letting the user select an existing picture from the photo library.

Expand the Camera folder so that you can get to all the relevant files. Select BIDViewController.h, and make the following changes:

#import <UIKit/UIKit.h>

#import <MediaPlayer/MediaPlayer.h>

@interface BIDViewController : UIViewController

<UIImagePickerControllerDelegate, UINavigationControllerDelegate>

@property (weak, nonatomic) IBOutlet UIImageView *imageView; @property (weak, nonatomic) IBOutlet UIButton *takePictureButton;

@property (strong, nonatomic) MPMoviePlayerController *moviePlayerController; @property (strong, nonatomic) UIImage *image;

@property (strong, nonatomic) NSURL *movieURL;

@property (copy, nonatomic) NSString *lastChosenMediaType; @property (assign, nonatomic) CGRect imageFrame;

-(IBAction)shootPictureOrVideo:(id)sender;

-(IBAction)selectExistingPictureOrVideo:(id)sender;

@end

The first thing you might notice is that we’ve actually conformed our class to two different protocols: UIImagePickerControllerDelegate and UINavigationControllerDelegate. Because UIImagePickerController is a subclass of

UINavigationController, we must conform our class to both of these protocols. The methods in UINavigationControllerDelegate are optional, and we don’t need either of them to use the image picker, but we need to conform to the protocol, or the compiler will give us a warning.

The other thing you might notice is that while we’ll be dealing with an instance of UIImageView for displaying a chosen image, we don’t have anything similar for displaying a chosen video. UIKit doesn’t include any publicly available class like UIImageView that works for showing video content, so instead, we’ll use an instance of MPMoviePlayerController, grabbing its view property and inserting it into our view hierarchy. This is a highly unusual way of using any view controller, but it’s actually the Apple-approved technique to show video inside a view hierarchy.

Everything else here is pretty straightforward, so save it. Now, select

BIDViewController.xib to edit the file in Interface Builder.

www.it-ebooks.info

CHAPTER 20: The Camera and Photo Library

679

Designing the Interface

Drag two Round Rect Buttons from the library to the window labeled View. Place them one above the other, aligning the bottom button with the bottom blue guideline. Doubleclick the top button, and give it a title of New Photo or Video. Then double-click the bottom button, and give it a title of Pick from Library. Next, drag an Image View from the library, and place it above the buttons. Expand the image view to take up the entire space of the view above the buttons, as shown earlier in Figure 20–2.

Now, control-drag from the File’s Owner icon to the image view, and select the imageView outlet. Drag again from File’s Owner to the New Photo or Video button, and select the takePictureButton outlet.

Next, select the New Photo or Video button, and bring up the connections inspector. Drag from the Touch Up Inside event to File’s Owner, and select the shootPictureOrVideo: action. Now, click the Pick from Library button, drag from the Touch Up Inside event in the connections inspector to File’s Owner, and select the selectExistingPictureOrVideo: action.

Once you’ve made these connections, save your changes and return to Xcode.

Implementing the Camera View Controller

Select BIDViewController.m, and make the following changes at the beginning of the file:

#import "BIDViewController.h"

#import <MobileCoreServices/UTCoreTypes.h>

@interface BIDViewController ()

static UIImage *shrinkImage(UIImage *original, CGSize size);

-(void)updateDisplay;

-(void)getMediaFromSource:(UIImagePickerControllerSourceType)sourceType;

@end

@implementation BIDViewController

.

.

.

As we’ve done a few times earlier in this book, we create a class extension to declare some methods that we don’t want to expose in our class’s interface, but that will be implemented at some later point in our class definition. The methods we put here are utility methods, meant only for use within the class itself. Note that we also declared a normal C function in this code. A class extension can really contain only methods, so this function doesn’t actually belong to the class extension, technically speaking. However, in terms of structuring our code, it “belongs” to our class, so we’ll list it here as well.

www.it-ebooks.info

680

CHAPTER 20: The Camera and Photo Library

Now, move along to start defining the class, as follows:

.

.

.

@implementation BIDViewController

@synthesize imageView; @synthesize takePictureButton;

@synthesize moviePlayerController; @synthesize image;

@synthesize movieURL; @synthesize lastChosenMediaType; @synthesize imageFrame;

- (void)viewDidLoad

{

[super viewDidLoad];

// Do any additional setup after loading the view, typically from a nib.

if (![UIImagePickerController isSourceTypeAvailable: UIImagePickerControllerSourceTypeCamera]) {

takePictureButton.hidden = YES;

}

imageFrame = imageView.frame;

}

.

.

.

- (void)viewDidAppear:(BOOL)animated

{

[super viewDidAppear:animated];

[self updateDisplay];

}

.

.

.

The viewDidLoad method will hide the takePictureButton if the device we’re running on does not have a camera, and it also grabs the imageView’s frame rect, since we’re going to need that a little later. We also implement the viewDidAppear: method, having it call the updateDisplay method, which we haven’t yet implemented.

It’s important to understand the distinction between the viewDidLoad and viewDidAppear: methods. The former is called only when the view has just been loaded into memory. The latter is called every time the view is displayed, which happens both at launch and whenever we return to our controller after showing another full-screen view, such as the image picker.

Next, insert the following lines of code into the existing viewDidUnload method. Normally, viewDidUnload only gets rid of views, but in this case, we’re also going to make it get rid of the moviePlayerController. Otherwise, we would have that controller hanging around even when there were no views left to show it in.

www.it-ebooks.info

CHAPTER 20: The Camera and Photo Library

681

.

.

.

- (void)viewDidUnload

{

[super viewDidUnload];

//Release any retained subviews of the main view.

//e.g. self.myOutlet = nil;

self.imageView = nil; self.takePictureButton = nil; self.moviePlayerController = nil;

}

.

.

.

Next, insert the following action methods that we declared in the header:

- (IBAction)shootPictureOrVideo:(id)sender {

[self getMediaFromSource:UIImagePickerControllerSourceTypeCamera];

}

- (IBAction)selectExistingPictureOrVideo:(id)sender {

[self getMediaFromSource:UIImagePickerControllerSourceTypePhotoLibrary];

}

Each of these simply calls out to one of the utility methods we declared earlier (but still haven’t defined), passing in a value defined by UIImagePickerController to specify where the picture or video should come from.

Next, let’s implement the delegate methods for the picker view:

#pragma mark UIImagePickerController delegate methods

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {

self.lastChosenMediaType = [info objectForKey:UIImagePickerControllerMediaType]; if ([lastChosenMediaType isEqual:(NSString *)kUTTypeImage]) {

UIImage *chosenImage = [info objectForKey:UIImagePickerControllerEditedImage]; UIImage *shrunkenImage = shrinkImage(chosenImage, imageFrame.size);

self.image = shrunkenImage;

} else if ([lastChosenMediaType isEqual:(NSString *)kUTTypeMovie]) { self.movieURL = [info objectForKey:UIImagePickerControllerMediaURL];

}

[picker dismissModalViewControllerAnimated:YES];

}

- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker { [picker dismissModalViewControllerAnimated:YES];

}

The first delegate method checks to see whether a picture or video was chosen, makes note of the selection (shrinking the chosen image, if any, to precisely fit the display size along the way), and then dismisses the modal image picker. The second one just dismisses the image picker.

www.it-ebooks.info

682

CHAPTER 20: The Camera and Photo Library

Next, let’s move on to the function and methods we declared as a class extension early in the file. First up is the shrinkImage() function, which we use to shrink our image down to the size of the view in which we’re going to show it. Doing so reduces the size of the UIImage we’re dealing with, as well as the amount of memory that imageView needs in order to display it. Add this code toward the end of the file:

#pragma mark -

static UIImage *shrinkImage(UIImage *original, CGSize size) { CGFloat scale = [UIScreen mainScreen].scale; CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

CGContextRef context = CGBitmapContextCreate(NULL, size.width * scale, size.height * scale, 8, 0, colorSpace, kCGImageAlphaPremultipliedFirst);

CGContextDrawImage(context,

CGRectMake(0, 0, size.width * scale, size.height * scale), original.CGImage);

CGImageRef shrunken = CGBitmapContextCreateImage(context); UIImage *final = [UIImage imageWithCGImage:shrunken];

CGContextRelease(context);

CGImageRelease(shrunken);

return final;

}

Don’t worry about the details too much. What you’re seeing here is a series of Core Graphics calls that create a new image based on the specified size and render the old image into the new one.

Note that we get a value called scale from the device’s main screen and use it as a multiplier when specifying the size of the new image we’re creating. The scale is basically the number of physical screen pixels per unit point in all the calls we make. Devices featuring “Retina display”, such as the iPhone 4, iPhone 4S, and fourthgeneration iPod touch, have a scale of 2.0; all other previous devices, and both iPad versions produced so var, will report 1.0. Using the scale this way lets us make an image that renders at the full resolution of the device on which we’re running. Otherwise, the image would end up looking a bit jagged on the iPhone 4 (if you looked really closely, that is).

Next up is the updateDisplay method. Remember that this is being called from the viewDidAppear: method, which is called both when the view is first created and then again after the user picks an image or video and dismisses the image picker. Because of this dual usage, it needs to make a few checks to see what’s what and set up the GUI accordingly. The MPMoviePlayerController doesn’t let us change the URL it reads from, so each time we want to display a movie, we’ll need to make a new controller. All of that is handled here. Add this code toward the bottom of the file:

- (void)updateDisplay {

if ([lastChosenMediaType isEqual:(NSString *)kUTTypeImage]) { imageView.image = image;

imageView.hidden = NO; moviePlayerController.view.hidden = YES;

www.it-ebooks.info

CHAPTER 20: The Camera and Photo Library

683

} else if ([lastChosenMediaType isEqual:(NSString *)kUTTypeMovie]) { [self.moviePlayerController.view removeFromSuperview]; self.moviePlayerController = [[MPMoviePlayerController alloc]

initWithContentURL:movieURL]; moviePlayerController.view.frame = imageFrame; moviePlayerController.view.clipsToBounds = YES; [self.view addSubview:moviePlayerController.view]; imageView.hidden = YES;

}

}

The final new method, getMediaFromSource:, is the one that both of our action methods call. This method is pretty simple. It just creates and configures an image picker, using the passed-in sourceType to determine whether to bring up the camera or the media library. Add this code toward the bottom of the file:

- (void)getMediaFromSource:(UIImagePickerControllerSourceType)sourceType { NSArray *mediaTypes = [UIImagePickerController

availableMediaTypesForSourceType:sourceType]; if ([UIImagePickerController isSourceTypeAvailable:

sourceType] && [mediaTypes count] > 0) { NSArray *mediaTypes = [UIImagePickerController

availableMediaTypesForSourceType:sourceType]; UIImagePickerController *picker = [[UIImagePickerController alloc] init]; picker.mediaTypes = mediaTypes;

picker.delegate = self; picker.allowsEditing = YES; picker.sourceType = sourceType;

[self presentModalViewController:picker animated:YES]; } else {

UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error accessing media"

message:@"Device doesn’t support that media source." delegate:nil

cancelButtonTitle:@"Drat!"

otherButtonTitles:nil];

[alert show];

}

}

@end

That’s all we need to do. Compile and run the app. If you’re running on the simulator, you won’t have the option to take a new picture. If you have the opportunity to run our application on a real device, go ahead and try it. You should be able to take a new picture, and zoom in and out of the picture using the pinch gestures.

If you zoom in before hitting the Use Photo button, the cropped image will be the one returned to the application in the delegate method.

www.it-ebooks.info

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]