Search code examples
iosiphoneobjective-ccamerauiimagepickercontroller

iPhone camera, how to avoid cameraOverlay on preivew view; How to know when entering preview view?


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.

enter image description here

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

Solution

  • 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

    #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;
    @property (nonatomic, strong) UIImagePickerController *picker;
    - (IBAction)takePhoto:(id)sender;
    - (IBAction)selectPhoto:(id)sender;
    @end
    

    CamViewController.h

    #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
    {
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleNotification:) name:@"_UIImagePickerControllerUserDidCaptureItem" object:nil ];
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleNotification:) name:@"_UIImagePickerControllerUserDidRejectItem" object:nil ];
    
        [super viewDidLoad];
        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)handleNotification:(NSNotification *)message {
        if ([[message name] isEqualToString:@"_UIImagePickerControllerUserDidCaptureItem"]) {
            // Remove overlay, so that it is not available on the preview view;
            self.picker.cameraOverlayView = nil;
        }
        if ([[message name] isEqualToString:@"_UIImagePickerControllerUserDidRejectItem"]) {
            // Retake button pressed on preview. Add overlay, so that is available on the camera again
            self.picker.cameraOverlayView = [self addCameraRollButton];
        }
    }
    
    -(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 {
        self.picker = [[UIImagePickerController alloc] init];
        self.picker.delegate = self;
        self.picker.allowsEditing = YES; // if this is NO or missing, the image the image will not be in info[UIImagePickerControllerEditedImage]
        self.picker.sourceType = UIImagePickerControllerSourceTypeCamera;
        self.picker.cameraOverlayView = [self addCameraRollButton];
    
        [self presentViewController:self.picker animated:YES completion:NULL];
    }
    
    -(void)prepareCameraRoll {
        isAction = 1;
        [self dismissViewControllerAnimated:NO completion:nil];
    
    }
    
    - (IBAction)selectPhoto:(id)sender {
    
        self.picker = [[UIImagePickerController alloc] init];
        self.picker.delegate = self;
        self.picker.allowsEditing = YES;
        self.picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
    
        [self presentViewController:self.picker animated:YES completion:NULL];
    }
    
    - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
    
        self.image = info[UIImagePickerControllerEditedImage]; 
    
        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 - CameraRoll function and presentation
    - (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;
    }
    
    -(void)cameraRoll {
        // have to import assetlibrary framework!!!
        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);
    }
    
    - (void)didReceiveMemoryWarning
    {
        [super didReceiveMemoryWarning];
    }
    
    @end