Reputation: 4869
I would like to show a countdown when the user hits the record button in the UIImagePicker controller but there is no delegate method telling us when they hit record. I'm able to set a max duration but I would like to give a 1 minute warning or something to that effect but I'm not sure how to do that
videoPickerCtrl = [[UIImagePickerController alloc] init];
videoPickerCtrl.delegate = self;
videoPickerCtrl.sourceType = UIImagePickerControllerSourceTypeCamera;
videoPickerCtrl.mediaTypes = [UIImagePickerController availableMediaTypesForSourceType:videoPickerCtrl.sourceType];
videoPickerCtrl.allowsEditing = NO;
videoPickerCtrl.videoMaximumDuration = 170;
videoPickerCtrl.mediaTypes = [NSArray arrayWithObject:(NSString *)kUTTypeMovie];
EDIT:
I could not find a solution to this so I made my own custom video picker controller. Hopefully someone else can find it useful: https://github.com/saliksyed/CustomVideoCapture
Upvotes: 2
Views: 2082
Reputation: 64
In a perfect world you'd want Apple to provide just a couple of delegates that would do that. For example :
Reality however (as per apple documentation) is that :
Documentation also states : "You can assign a custom view to the cameraOverlayView property and use that view to present additional information or manage the interactions between the camera interface and your code".
In my application I needed to present "UIProgressView" to indicate how much longer the video could be recorded. In order to accomplish that I needed to be able to detect the moment video capturing started.
I didn't want to disable native camera controls because they are cool and I'm lazy so that I didn't want to spend much time reinventing the wheel. Simply all I needed was to capture the fact that a big RED button was tapped to either start or stop recording.
My solution was to "cover" original Start/Stop recording button with a custom view and enable user interaction for that view as follow :
overlayView = [[UIView alloc] initWithFrame:self.view.frame];
// Start/ Stop fake button
UIView *ssView = [[UIView alloc] initWithFrame:CGRectMake(self.view.frame.size.width / 2 - 35, self.view.frame.size.height - 71, 70, 70)];
[ssView setUserInteractionEnabled:YES];
// Background color below is only there to make sure my pseudo-button overlaps native Start/Stop button. Comment out the line below to leave it transparent
[ssView setBackgroundColor:[UIColor colorWithRed:0 green:1 blue:0 alpha:0.5f]];
UITapGestureRecognizer *t = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapped:)];
[ssView addGestureRecognizer:t];
[overlayView addSubview:ssView];
// My own progress bar
UIProgressView *p = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault];
[p setTintColor:[UIColor redColor]];
[p setCenter:CGPointMake(30, 130)];
[p setTransform:CGAffineTransformMakeRotation( M_PI / 2 )];
[p setProgress:0];
[overlayView addSubview:p];
pickerController.cameraOverlayView = overlayView;
I then defined event handler for a tap as follow :
-(void)tapped:(id)sender {
if (isRecording) {
[pickerController stopVideoCapture];
NSLog(@"Video capturing stopped...");
// add your business logic here ie stop updating progress bar etc...
[pickerController.cameraOverlayView setHidden:YES];
isRecording = NO;
return;
}
if ([pickerController startVideoCapture]) {
NSLog(@"Video capturing started...");
// add your business logic here ie start updating progress bar etc...
isRecording = YES;
}
}
Full code of the interface file :
#import <UIKit/UIKit.h>
#import <MobileCoreServices/MobileCoreServices.h>
@interface ViewController : UIViewController <UIImagePickerControllerDelegate>
- (IBAction)openCamera:(id)sender;
@end
Implementation file :
#import "ViewController.h"
@interface ViewController () {
UIImagePickerController *pickerController;
UIView* overlayView;
BOOL isRecording;
}
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
isRecording = NO;
pickerController = [[UIImagePickerController alloc] init];
pickerController.delegate = self;
pickerController.allowsEditing = NO;
pickerController.videoMaximumDuration = 30.0f;
pickerController.sourceType = UIImagePickerControllerSourceTypeCamera;
pickerController.mediaTypes = [[NSArray alloc] initWithObjects: (NSString *) kUTTypeMovie, nil];
// I want default controls be available here...
pickerController.showsCameraControls = YES;
overlayView = [[UIView alloc] initWithFrame:self.view.frame];
// Start/ Stop fake button
UIView *ssView = [[UIView alloc] initWithFrame:CGRectMake(self.view.frame.size.width / 2 - 35, self.view.frame.size.height - 71, 70, 70)];
[ssView setUserInteractionEnabled:YES];
// Background color below is only there to make sure myt pseudo-button overlaps native Start/Stop button
[ssView setBackgroundColor:[UIColor colorWithRed:0 green:1 blue:0 alpha:0.5f]];
UITapGestureRecognizer *t = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapped:)];
[ssView addGestureRecognizer:t];
[overlayView addSubview:ssView];
// My own progress bar
UIProgressView *p = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault];
[p setTintColor:[UIColor redColor]];
[p setCenter:CGPointMake(30, 130)];
[p setTransform:CGAffineTransformMakeRotation( M_PI / 2 )];
[p setProgress:0];
[overlayView addSubview:p];
pickerController.cameraOverlayView = overlayView;
}
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
// Cancel button tapped
[picker dismissViewControllerAnimated:YES completion:nil];
}
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
NSLog(@"Got image : %@", info);
[picker dismissViewControllerAnimated:YES completion:nil];
// Do something with video captured
}
-(void)tapped:(id)sender {
if (isRecording) {
[pickerController stopVideoCapture];
NSLog(@"Video capturing stopped...");
// add your business logic here ie stop updating progress bar etc...
[pickerController.cameraOverlayView setHidden:YES];
isRecording = NO;
return;
}
if ([pickerController startVideoCapture]) {
NSLog(@"Video capturing started...");
// add your business logic here ie start updating progress bar etc...
isRecording = YES;
}
}
- (IBAction)openCamera:(id)sender {
[pickerController.cameraOverlayView setHidden:NO];
[self presentViewController:pickerController animated:YES completion:nil];
}
@end
You might have noticed that I'm hiding cameraOverlayView once video capturing is stopped.
[pickerController.cameraOverlayView setHidden:YES];
This is to allow "Retake / Play and Use" native controls to work properly after video has been recorded.
Upvotes: 1
Reputation: 3106
For anyone else, this can be done if you use a custom overlay view on the UIImagePickerController
. Just add all the controls you want to a view and then set that parent view to the property cameraOverlayView
.
Upvotes: 0
Reputation: 1032
I created the same effect you're looking for by using a custom overlay view.
You need to create a modal window with an instance of UIVideoEditorController
who's videoPath
property is the UIImagePickerControllerMediaURL
key in userInfo
from the imagePickerController:didFinishPickingMediaWithInfo:
method you should be handling.
HTH
Upvotes: 0
Reputation: 4869
Okay. So I'm pretty sure what I want to achieve is just not possible. I'm going to just re-create the standard UIImagePickerController interface for videos using AVFoundation as the backend. Hopefully once it is done I'll post it on github or something.
Upvotes: 0
Reputation: 135550
You don't get notified when the user taps the button but you can provide your own record button: set the image picker to hide its standard controls (showsCameraControls
) and provide a custom overlay view (cameraOverlayView
). In that overlay view, place a custom button that you connect to a target/action, and in the action method you call -startVideoCapture
.
Upvotes: 0