Custom Camera App | Part 1: Custom Overlay

First part of the Custom Camera App series.

In this series, I will teach you how to create your own camera app using UIImagePickerController.

The series is divided into 3 parts, and in this first part I will explain how to create the custom overlay for our camera.

The class UIImagePickerController allows you to easily access images in the iPhone, and to make photos or videos. You can use the default camera interface provided by Apple, but today we will create our own UI for it.

Step 1

First, create a UIViewController subclass and name it CameraViewController. This class needs to adopt the UIImagePickerControllerDelegate and UINavigationController protocols, and we will also need a property for our UIImagePickerController, so go to the header file and write the following:

#import <UIKit/UIKit.h>

@interface CameraViewController : UIViewController <UIImagePickerControllerDelegate, UINavigationControllerDelegate>

@property (nonatomic, strong) UIImagePickerController *picker;

@end

Now, synthesize it in the implementation file. In the viewDidLoad method, we need to set the initial attributes for our UIImagePickerController. To use our custom overlay, we need to hide the navigation bar and also the toolbar. Moreover, we need to set a delegate, which will be self in this case, and we also need to specify if we want a full-screen layout.

There are other attributes we will need to set for the overlay when the user is going to take a photo, but we will put them in the method showCamera, since we will need to call this method and set again those attributes more than once.

- (void)viewDidLoad
{
// Do any additional setup after loading the view, typically from a nib.
[super viewDidLoad];

// Initialize our custom overlay.
overlay = [[CustomOverlayView alloc]
initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGTH)];

overlay.delegate = self;

self.picker = [[UIImagePickerController alloc] init];
self.picker.delegate = self;
self.picker.navigationBarHidden = YES;
self.picker.toolbarHidden = YES;
self.picker.wantsFullScreenLayout = YES;

[self showCamera];
}

We will leave the showCamera method for the second part of the series, and focus on the custom overlay.

Step 2

Our overlay must be a subclass of UIView, so create a new UIView subclass and name it CustomOverlayView. In this class we are going to add programmatically all the buttons we need, and we will set CameraViewController as its delegate to send messages to it when the user presses a button. We are going to need at least two buttons, one to take the picture and the other one to go to the photo library, and we will add a bottom bar to make it nicer.

- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {

self.opaque = NO;

// Add the bottom bar
UIImage *image = [UIImage imageNamed:@"bar"];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
imageView.frame = CGRectMake(0, 415, 320, 65);
[self addSubview:imageView];

// Add the capture button
self.pictureButton = [UIButton buttonWithType:UIButtonTypeCustom];
self.pictureButton.frame = CGRectMake(90, 385, 130, 100);
UIImage *buttonImageNormal = [UIImage imageNamed:@"take_picture"];
[self.pictureButton setImage:buttonImageNormal forState:UIControlStateNormal];
[self.pictureButton setImage:buttonImageNormal forState:UIControlStateDisabled];
[self.pictureButton addTarget:self action:@selector(takePicture:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:self.pictureButton];

// Add the gallery button
self.lastPicture = [UIButton buttonWithType:UIButtonTypeCustom];
self.lastPicture.frame = CGRectMake(20, 423, 50, 50);
[self.lastPicture addTarget:self action:@selector(showCameraRoll:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:self.lastPicture];
}
return self;
}

Step 3

Since we want a camera app with full functionality, we also need to add a button to control the flash and a button to change the camera. However, this is not available in all devices. For example, an iPhone 3G does not have a front camera. Therefore, we need to control this and only display these buttons if the device supports it:

- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {

self.opaque = NO;

UIImage *buttonImageNormal;

// Add the flash button
if ([UIImagePickerController isFlashAvailableForCameraDevice:UIImagePickerControllerCameraDeviceRear]) {
self.flashButton = [UIButton buttonWithType:UIButtonTypeCustom];
self.flashButton.frame = CGRectMake(10, 30, 57.5, 57.5);
buttonImageNormal = [UIImage imageNamed:@"flash02"];
[self.flashButton setImage:buttonImageNormal forState:UIControlStateNormal];
[self.flashButton addTarget:self action:@selector(setFlash:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:self.flashButton];
}

// Add the camera button
if ([UIImagePickerController isCameraDeviceAvailable:UIImagePickerControllerCameraDeviceFront]) {
self.changeCameraButton = [UIButton buttonWithType:UIButtonTypeCustom];
self.changeCameraButton.frame = CGRectMake(250, 30, 57.5, 57.5);
buttonImageNormal = [UIImage imageNamed:@"switch_button"];
[self.changeCameraButton setImage:buttonImageNormal forState:UIControlStateNormal];
[self.changeCameraButton addTarget:self action:@selector(changeCamera:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:self.changeCameraButton];
}

// Add the bottom bar
UIImage *image = [UIImage imageNamed:@"bar"];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
imageView.frame = CGRectMake(0, 415, 320, 65);
[self addSubview:imageView];

// Add the capture button
self.pictureButton = [UIButton buttonWithType:UIButtonTypeCustom];
self.pictureButton.frame = CGRectMake(90, 385, 130, 100);
buttonImageNormal = [UIImage imageNamed:@"take_picture"];
[self.pictureButton setImage:buttonImageNormal forState:UIControlStateNormal];
[self.pictureButton setImage:buttonImageNormal forState:UIControlStateDisabled];
[self.pictureButton addTarget:self action:@selector(takePicture:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:self.pictureButton];

// Add the gallery button
self.lastPicture = [UIButton buttonWithType:UIButtonTypeCustom];
self.lastPicture.frame = CGRectMake(20, 423, 50, 50);
[self.lastPicture addTarget:self action:@selector(showCameraRoll:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:self.lastPicture];
}
return self;
}

Step 4

Once we have created the buttons we need, it’s time to implement the methods that will be called whenever the user presses a button. As you can see in the code, we have a total of four methods that will call a method on the delegate, so its implementation is pretty straightforward.

However, when the user takes a picture we will use a little trick so that, if the user presses the takePicture button more than once while the photo is being taken, these additional presses will be ignored.

- (void)takePicture:(id)sender
{
self.pictureButton.enabled = NO;
[self.delegate takePicture];
}

- (void)setFlash:(id)sender
{
[self.delegate changeFlash:sender];
}

- (void)changeCamera:(id)sender
{
[self.delegate changeCamera];
}

- (void)showCameraRoll:(id)sender
{
[self.delegate showLibrary];
}

Step 5

Xcode must be complaining by now about undefined variables, since we did not declare the delegate for our custom overlay view in the header file. Moreover, we will need properties for each of the buttons we have just created, as we will use them in the controller in the next tutorial. Hence, add all of it to your header file:

#import <UIKit/UIKit.h>
#import "CameraViewController.h"

@interface CustomOverlayView : UIView

@property (nonatomic, weak) CameraViewController *delegate;
@property (nonatomic, weak) UIButton *pictureButton;
@property (nonatomic, weak) UIButton *flashButton;
@property (nonatomic, weak) UIButton *changeCameraButton;
@property (nonatomic, weak) UIButton *lastPicture;

@end

Don’t forget to synthesize these 5 properties in your implementation file.

Conclusion

That’s it for today. In the next part of this series, I will talk about the view controller we created, and how to use UIImagePickerController. If you have any doubts, leave a comment.

Comment policy: Respectful and beneficial comments are welcome with full open hands. However, all comments are manually moderated and those that doesn't relate with what the passage is saying or offensive comments would be deleted. Thanks for understanding!

Leave a Reply

Your email address will not be published. Required fields are marked *