I've noticed that in OS 3.1 you can add an overlay view to the image picker with
cameraOverlayView
However, I've also noticed that adding a view via this method also displays the view for the entire time the UIImagePicker is displayed, when I only want to show it during the preview stage.
Is there a way to make this only happen during preview? I don't want it to be there during the open shutter animation, or the screen that asks whether you want to use the image or retake.
I've figured out a way for you to achieve the desired result though it's a bit... not so standard. :)
The idea is to rearrange a bit the order of the inner views in the structure UIImagePickerController
uses.
OK, so we create an UIImagePickerController
object, initialize it and add an overlay view to it. May I have your attention please! The UIView
object (UIImageView
in the example code) is hidden from the very beginning. Don't miss that. Finally we present the image picker controller as modal view controller. This code should be somewhere in your applicationDidFinishLaunching:
, viewWillAppear:
or similar appropriate about to launch methods.
UIImagePickerController *anImagePickerController = [UIImagePickerController new];
anImagePickerController.delegate = self;
anImagePickerController.sourceType = UIImagePickerControllerSourceTypeCamera;
UIImageView *anImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"Watermark.png"]];
anImageView.frame = CGRectMake(0, 1, anImageView.image.size.width, anImageView.image.size.height);
anImageView.hidden = YES;
anImagePickerController.cameraOverlayView = anImageView;
[viewController presentModalViewController:anImagePickerController animated:NO];
[anImagePickerController release];
[NSTimer scheduledTimerWithTimeInterval:0.1
target:self
selector:@selector(timerFireMethod:)
userInfo:anImageView
repeats:YES];
[anImageView release];
Before the overlay view (anImageView
) is released a NSTimer
is created, initialized with anImageView
(NSTimer
userInfo
property) and scheduled right away. Here's the method it calls:
- (void)timerFireMethod:(NSTimer*)theTimer {
UIView *cameraOverlayView = (UIView *)theTimer.userInfo;
UIView *previewView = cameraOverlayView.superview.superview;
if (previewView != nil) {
[cameraOverlayView removeFromSuperview];
[previewView insertSubview:cameraOverlayView atIndex:1];
cameraOverlayView.hidden = NO;
[theTimer invalidate];
}
}
The whole NSTimer
thing is added to the flow to ensure that the reordering work around will happen exactly when the UIImagePickerController
will be totally ready for that.
This is it. It works, it's not standard, it's rough and quick. Again feel free to optimize and make it 'righter' (oh please do, my aim was to show you the way).
I just wanted to show up another possibility without subview fiddling.
There are system notifications for the changes in the CameraPicker. They are not documented either (as the subview structure). So they are also subject to change. BUT you get them.
You can register for them using no name:
[[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(notificationReceived:) name: nil object: nil];
We get some interesting (selfexplaining) notifications here:
PLCameraControllerPreviewStartedNotification
PLCameraViewIrisAnimationWillBeginNotification
PLCameraViewIrisAnimationDidEndNotification
Recorder_DidStartPreviewing
Recorder_SourceStarted
Recorder_WillCapturePhoto
Recorder_DidCapturePhoto
Recorder_PhotoStillImageSampleBufferReady
Recorder_DidStopPreviewing
_UIImagePickerControllerUserDidCaptureItem // Photo was taken, preview is shown
_UIImagePickerControllerUserDidRejectItem // Repeat was pressed, camera is shown again
You could use them, to trigger your overlayviews hidden state or anything else.
Actually, I was trying to do the same thing and I came across a much simpler of doing it via this blog post: http://www.alexcurylo.com/blog/2009/06/18/uiimagepickercontroller-in-3-0/
Since the UIImagePickerController can call a UINavigatorControllerDelegate, the method below gets called before the Image picker is displayed.
Here's the important code:
- (void)navigationController:(UINavigationController *)navigationController
willShowViewController:(UIViewController *)viewController
animated:(BOOL)animated
{
if (!viewController)
return;
UIView* controllerViewHolder = viewController.view;
UIView* controllerCameraView = [[controllerViewHolder subviews] objectAtIndex:0];
UIView* controllerPreview = [[controllerCameraView subviews] objectAtIndex:0];
[controllerCameraView insertSubview:self.overlayView aboveSubview:controllerPreview];
}
Hope that helps.
When you build up the picker add the overlay to the picker (picker.cameraOverlayView = myView).
The overlay will not be in the picture taken. It is just, like it says, an overlay view.
You can remove the overlay view before taking a picture (takePicture
method) and add the view again in imagePickerController:didFinishPickingMediaWithInfo: