On the camera workflow, the photo is captured and on the next screen, let's call it choose-screen, you can choose if you want to use this photo or retake it.
How do I know, when the camera enteres the preview view?
My issue is that I have added a button to access the camera roll, which works fine. The obstacle is, when taking a photo and entering the preview view (2. Camera View), the button hides the "use photo" option. So I cannot select it. I want to hide the button when entering the preview view or just avoid the preview view.
Below my code
CamViewScreen.h
#import <UIKit/UIKit.h>
#import "CameraViewController.h"
#import <AssetsLibrary/AssetsLibrary.h>
@interface CamViewController : UIViewController <UIImagePickerControllerDelegate, UINavigationControllerDelegate>
@property (nonatomic, strong) UIImage *image;
@property (nonatomic, strong) UIImage *lastTakenImage;
- (IBAction)takePhoto:(id)sender;
- (IBAction)selectPhoto:(id)sender;
@end
CamViewScreen.m
#import "CamViewController.h"
@interface CamViewController ()
@end
@implementation CamViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
int isAction = 0; // Photo, 1: CameraRoll, 2: Cancel
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
UIAlertView *myAlertView = [[UIAlertView alloc] initWithTitle:@"Error"
message:@"Device has no camera"
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles: nil];
[myAlertView show];
}
isAction = 0;
[self cameraRoll];
}
-(void)viewDidAppear:(BOOL)animated {
// isAction = 0 Photo, 1: CameraRoll, 2: Cancel
DLog(@"###### isAction> %d", isAction);
switch (isAction) {
case 1:
[self selectPhoto:nil];
break;
case 2:
[self dismissViewControllerAnimated:NO completion:nil];
break;
default:
[self takePhoto:nil];
break;
}
}
- (IBAction)takePhoto:(id)sender {
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
picker.allowsEditing = NO;
picker.sourceType = UIImagePickerControllerSourceTypeCamera;
picker.cameraOverlayView = [self addCameraRollButton]; // suggestion from omz
// [self addCameraRollButton:picker.view];
[self presentViewController:picker animated:YES completion:NULL];
}
-(void)prepareCameraRoll {
isAction = 1;
[self dismissViewControllerAnimated:NO completion:nil];
}
- (IBAction)selectPhoto:(id)sender {
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
picker.allowsEditing = YES;
picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
[self presentViewController:picker animated:YES completion:NULL];
}
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
UIImage *chosenImage = info[UIImagePickerControllerEditedImage];
self.image = chosenImage;
isAction = 0;
[picker dismissViewControllerAnimated:YES completion:NULL];
[self performSegueWithIdentifier:@"toCameraView" sender:info];
}
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
isAction = 2; // Cancel
[picker dismissViewControllerAnimated:YES completion:NULL];
}
# pragma mark - for the cameraOverlayView // suggestion from omz
- (UIView *)addCameraRollButton {
float startY = ([[UIScreen mainScreen] bounds].size.height == 568.0) ? 500.0 : 410.0;
UIButton *rollButton = [UIButton buttonWithType:UIButtonTypeCustom];
rollButton.frame = CGRectMake(230.0, startY, 60.0, 60.0);
rollButton.backgroundColor = [UIColor clearColor];
[rollButton setImage:self.lastTakenImage forState:UIControlStateNormal];
rollButton.imageView.contentMode = UIViewContentModeScaleAspectFill;
[rollButton addTarget:self action:@selector(prepareCameraRoll) forControlEvents:UIControlEventTouchUpInside];
return rollButton;
}
# pragma mark - CameraRoll function and presentation
- (void)addCameraRollButton:(UIView *)picker {
float startY = ([[UIScreen mainScreen] bounds].size.height == 568.0) ? 500.0 : 410.0;
UIButton *rollButton = [UIButton buttonWithType:UIButtonTypeCustom];
rollButton.frame = CGRectMake(230.0, startY, 60.0, 60.0);
rollButton.backgroundColor = [UIColor clearColor];
[rollButton setImage:self.lastTakenImage forState:UIControlStateNormal];
rollButton.imageView.contentMode = UIViewContentModeScaleAspectFill;
[rollButton addTarget:self action:@selector(prepareCameraRoll) forControlEvents:UIControlEventTouchUpInside];
[picker addSubview:rollButton];
}
-(void)cameraRoll {
ALAssetsLibrary *assetsLibrary = [[ALAssetsLibrary alloc] init];
[assetsLibrary enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos
usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
if (nil != group) {
// be sure to filter the group so you only get photos
[group setAssetsFilter:[ALAssetsFilter allPhotos]];
[group enumerateAssetsWithOptions:NSEnumerationReverse usingBlock:^(ALAsset *asset, NSUInteger index, BOOL *stop) {
if (asset) {
ALAssetRepresentation *repr = [asset defaultRepresentation];
// UIImage *img = [UIImage imageWithCGImage:[repr fullResolutionImage]];
UIImage *img = [UIImage imageWithCGImage:[repr fullScreenImage]];
[self setLastTakenImage:img];
*stop = YES;
}
}];
}
*stop = NO;
} failureBlock:^(NSError *error) {
NSLog(@"error: %@", error);
}];
}
#pragma mark - Navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
CameraViewController *cvc = [segue destinationViewController];
cvc.image = self.image;
DLog(@"%@, cvcimage", cvc.image);
}
@end
Just posting here for future Swift references, if anyone needs it.
I've been having the same issue, and after a day of research, with a lot of trail and error, I found a way that removes the cameraOverlayView from the image preview.
When you take a photo the "_UIImagePickerControllerUserDidCaptureItem" triggers. Luckily we can utilize this by creating an observer with a closure. Inside the closure we can set the cameraOverlayView to nil, and thereby removing your custom view before entering preview.
This works in Xcode Version 8.1 (8B62), with Swift 3.
I have added the code snippet for you to utilize if needed.
Found a solution. Was hard to find, but finally got it. The solution is described at UIImagePicker cameraOverlayView appears on Retake screen. Additionally I add my working code for others who have the same problem.
The use of the
NSNotificationCenter
with @"_UIImagePickerControllerUserDidCaptureItem" and @"_UIImagePickerControllerUserDidRejectItem" is the key!CamViewController.h
CamViewController.h
In swift 4 for future references. I'm using isHidden because I had problems to show it back when the user select Retake.
@jerik-I saw you amended your question. You can set the UIImagePickerController property
showsCameraControls
to no, which will eliminate the preview screen- this hides the default controls as well (and lets you take multiple pictures without dismissing the camera), but since you are usingcameraOverlayView
, it's immaterial. This only works if the media type is camera, and you will have to implement thetakePicture
function of the UIImagePickerDelegate protocol to take the picture programatically.I haven't tried the hack of changing the controls of the preview screen. If you really want to keep the preview screen, you need to add logic to your own
takePhoto
function that determines if you should callpicker.cameraOverlayView = [self addCameraRollButton]
(taking a picture) or not (the preview screen), but I'm not sure if you can change the cameraOverlayView for the preview screen dynamically - it seems like something Apple wouldn't want you messing with. Anyway, good luck!