Reputation: 2520
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
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
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
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
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
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
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
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