Jan
Jan

Reputation: 2520

DIsmissing a UIImagePickerController is also making the parent dissapear

I'm using the following code to show a UIImagePickerController to take a picture:

UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
[imagePicker setDelegate:self];    
[imagePicker setSourceType:UIImagePickerControllerSourceTypeCamera];
[self presentViewController:imagePicker animated:YES completion:nil];

Note: self is a UIViewController embedded inside a Container View, which itself takes part in a UINavigationController

And I have also implemented the following methods:

-(void) imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
    UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];  
    [self.imgProfile setImage:image];   
    [self dismissViewControllerAnimated:YES completion:nil];    
}

- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
{
    [self dismissViewControllerAnimated:YES completion:nil];
}

When I either choose the picture taken or cancel it, the UIImagePickerController goes away, but also the main view disappears! With a Fade to Black.

I'm coding for iOS7 on an iPad only app, in case it has anything to do with it.

Here is a video that shows the problem. Excuse the blur, but it is under an NDA.

http://www.youtube.com/watch?v=sIaPyRlIqyE

Upvotes: 5

Views: 7105

Answers (7)

g.Rapido
g.Rapido

Reputation: 157

Try setting your image picker's .modalPresentationStyle to either .OverCurrentContext or .OverFullScreen:

Alternately:

viewController.definesPresentationContext = true
imagePicker.modalPresentationStyle = .CurrentContext OR .FullScreen

The point being that the relationship between those two properties needs to be preserved as such: if false then .OverCurrentContext, if true then .CurrentContext

In my case, my view controller's .definesPresentationContext was defaulting to false, so I used the first option.

See documentation for some insight.

Upvotes: 6

myron
myron

Reputation: 11

Just for notice, UIImagePickerController's delegate is "double delegate", it also delegate UINavigationControllerDelegate. See the code below.

@property(nullable,nonatomic,weak) id <UINavigationControllerDelegate, UIImagePickerControllerDelegate> delegate;

So, check if self also implement UINavigationControllerDelegate, and dismiss parent viewcontroller like below.

- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated{
    NSMutableArray *stack = [navigationController.viewControllers mutableCopy];
    if (stack.count >= 2) {
        [stack removeObjectAtIndex:(stack.count-2)];
    }
    navigationController.viewControllers = [stack copy];
    navigationController.delegate = nil;
}

Ok, I did and it cost me lots of time to find out. My situation may be not the common case. This is just for reference.

Upvotes: 0

vedrano
vedrano

Reputation: 2971

I had similar but not exact problem when I was trying to present UIImagePickerController from within UIContainerView.

Problem was that dismissing UIImagePickerController changed navigation in the very UIContainerView (resized to full-screen).

Solution was to present UIImagePickerController from within PARENT view controller of UIContainerView and now everything works perfectly.

Upvotes: 0

Gili Ariel
Gili Ariel

Reputation: 602

You should dismiss the picker, not your view (self) and be sure to add these:

<UINavigationControllerDelegate, UIImagePickerControllerDelegate>

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {

UIImage *chosenImage = info[UIImagePickerControllerEditedImage];
self.imageView.image = chosenImage;

[picker dismissViewControllerAnimated:YES completion:NULL];

}

- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {

[picker dismissViewControllerAnimated:YES completion:NULL];

}

Upvotes: 3

Gazzini
Gazzini

Reputation: 738

When the UIImagePickerController officially dismisses, it triggers the following methods on whatever VC is immediately behind it in the navigation stack:

- viewWillAppear
- viewDidAppear
- viewDidLayoutSubviews
a bunch of other methods having to do with basic VC lifecycle.

In my case, I wasn't presenting the topmost VC using the presentViewController: method. I was instantiating it as a child of the root VC and doing some custom animations. I was doing most of this work in the -viewDidLayoutSubviews method. Part of this work was specifying that the frame of my child view in an off-screen position.

So, when I animated my child view onto the screen, presented the camera, and then dismissed it, the app eventually triggered the -viewDidLayoutSubviews on my rootVC, which moved my childVC off-screen.

So, I guess the answer is to make sure that the initial VC setup code can only be triggered once (use something like Bool setupHasAlreadyHappenedOnce before laying everything out).

Upvotes: 1

Malcolm Sparrow
Malcolm Sparrow

Reputation: 141

I've encountered the same issue under iOS7, and the only solution I've found is do to as follows;

When presenting the picker from your VC ;

UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
picker.allowsEditing = YES;
picker.sourceType = UIImagePickerControllerSourceTypeCamera;
picker.mediaTypes = [[NSArray alloc] initWithObjects: (NSString *) kUTTypeMovie, nil];

[self addChildViewController:picker] ;

[picker didMoveToParentViewController:self] ;

[self.view addSubview:picker.view] ;

Then, when handling the picker delegates - instead of dismissModal, use ;

[picker.view removeFromSuperview] ;
[picker removeFromParentViewController] ;

All you lose is the animated present/dismiss - other than that, all should be well.

Upvotes: 14

D-eptdeveloper
D-eptdeveloper

Reputation: 2430

It's recommended to use UIPopOver while you're opening the camera roll to iPad like this so give it a try hope it helps you.

#pragma mark
#pragma mark - Image Picker
-(IBAction)onClickTakePhoto:(id)sender
{
    if([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])
    {

        imagePickerController = [[UIImagePickerController alloc] init];        
        imagePickerController.delegate = self;
        imagePickerController.sourceType = UIImagePickerControllerSourceTypeCamera;
        imagePickerController.mediaTypes = [UIImagePickerController  availableMediaTypesForSourceType:imagePickerController.sourceType];
        imagePickerController.allowsEditing = YES;

        if ([self respondsToSelector:@selector(presentViewController:animated:completion:)]) {
            [self presentViewController:imagePickerController animated:YES completion:nil];
        } else {
            [self presentModalViewController:imagePickerController animated:YES];
        }        
        [imagePickerController release];
    }
}

-(IBAction)onClickChooseFromLibrary:(id)sender
{
    if([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeSavedPhotosAlbum])
    {
        imagePickerController = [[UIImagePickerController alloc] init];
        imagePickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
        imagePickerController.delegate = self;
        imagePickerController.allowsEditing = YES;
        imagePickerController.mediaTypes = [UIImagePickerController  availableMediaTypesForSourceType:imagePickerController.sourceType];
        popoverController= [[UIPopoverController alloc]
                        initWithContentViewController:imagePickerController];
        [popoverController presentPopoverFromRect:btnLibrary.frame inView:self.view permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
    }
}

#pragma mark
#pragma mark - UIImagePickerDelegate
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
{    
    if ([self respondsToSelector:@selector(dismissViewControllerAnimated:completion:)])   
    {
        [self dismissViewControllerAnimated:YES completion:nil];
    } else {
        [self dismissModalViewControllerAnimated:YES];
    }
    [popoverController dismissPopoverAnimated:YES];
}

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{    
    if ([self respondsToSelector:@selector(dismissViewControllerAnimated:completion:)]) 
    {
        [self dismissViewControllerAnimated:YES completion:nil];
    } else {
        [self dismissModalViewControllerAnimated:YES];
    }

    [popoverController dismissPopoverAnimated:YES];
    UIImage *image = [info objectForKey:UIImagePickerControllerEditedImage];
    [userImage setLocalImage:image];
}

Upvotes: 0

Related Questions