I need to display the image picker when the user enters into ViewControllerA and stay there after the user made a photo and pressed "Use Photo" button.
Actually the problem comes out when the user tap the "Use Photo" button, in this case the image picker pops up again time after time. I know it's because the viewWillAppear, but the viewDidLoad also not a good choice, because in this case the image picker won't be appear more than 1 time.
Possibly somebody could give me some guidance that how can I close the image picker without this issue? I just want to display it everytime the user enters in the view controller and close it after the user has choosen an image.
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
self.imagePicker = [[UIImagePickerController alloc] init];
self.imagePicker.delegate = self;
self.imagePicker.allowsEditing = YES;
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
self.imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
}
self.imagePicker.mediaTypes = [NSArray arrayWithObject:(NSString *)kUTTypeImage];
[self presentViewController:self.imagePicker animated:NO completion:nil];
}
- (void) imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
UIImage *choosenImage = info[UIImagePickerControllerEditedImage];
self.placeholderImg.image = choosenImage;
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void) imagePickerControllerDidCancel:(UIImagePickerController *)picker {
[self dismissViewControllerAnimated:NO completion:nil];
[self.tabBarController setSelectedIndex:1];
}
In your view controller's .m file you can declare a BOOL that will keep up if you've presented the UIImagePickerController already.
#interface MyCustomViewController ()
{
BOOL imagePickerHasBeenPresented;
}
#end
And then in your viewWillAppear method check that bool:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
if (imagePickerHasBeenPresented == NO)
{
imagePickerHasBeenPresented = YES;
//Code to present imagePicker
}
}
Related
I have a problem where the delegate of UIImagePickerController not being called when presented with sourceType = UIImagePickerControllerSourceTypePhotoLibrary.
Oddly enough, it works perfectly fine in camera mode.
Interface declaration:
#interface ChatVC : UIViewController <UIActionSheetDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate>
And in implementation:
- (void)takePhotoAction {
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
UIImagePickerController* imgPickerController = [[UIImagePickerController alloc] init];
imgPickerController.sourceType = UIImagePickerControllerSourceTypeCamera;
imgPickerController.cameraCaptureMode = UIImagePickerControllerCameraCaptureModePhoto;
imgPickerController.allowsEditing = YES;
imgPickerController.delegate = self;
[self presentViewController:imgPickerController animated:YES completion:nil];
}
}
- (void)choosePhotoFromLibraryAction {
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) {
UIImagePickerController* imgPickerController = [[UIImagePickerController alloc] init];
imgPickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
imgPickerController.allowsEditing = YES;
imgPickerController.delegate = self;
[self presentViewController:imgPickerController animated:YES completion:nil];
}
}
And here's the delegate method implementation in the same view controller:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)image editingInfo:(NSDictionary<NSString *,id> *)editingInfo {
NSLog(#"Image Picker Controller Picked Image - Deprecated");
[picker dismissViewControllerAnimated:YES completion:nil];
}
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
NSLog(#"Image Picker Controller Picked Image");
[picker dismissViewControllerAnimated:YES completion:nil];
}
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
NSLog(#"Image Picker Controller Cancelled");
[picker dismissViewControllerAnimated:YES completion:nil];
}
When opened in camera mode, everything works just fine, and I can see the appropriate delegate methods being called.
But when opened in photo library mode and I choose a photo, nothing happens and no delegate method is called. However, I can see -imagePickerControllerDidCancel: delegate method being called when I tap on Cancel button.
I even suspected memory warning somehow invalidates the delegate, but it was not the case here.
Please someone help me figure this out.
Thanks in advance!
This application loads the device's camera in viewWillAppear method:
- (void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
if (self.imageView.image == nil) {
UIImagePickerController *imagePickerController = [[UIImagePickerController alloc] init];
imagePickerController.sourceType = UIImagePickerControllerSourceTypeCamera;
imagePickerController.modalPresentationStyle = UIModalPresentationCurrentContext;
imagePickerController.delegate = self;
[self presentViewController:imagePickerController animated:YES completion:nil];
}
else { }
}
Delegate methods are implemented:
- (void) imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
UIImage *image = [info objectForKey:#"UIImagePickerControllerOriginalImage"];
[self dismissViewControllerAnimated:YES completion:nil];
// Pass the image to email composer after dismissing the camera. Delay allowed for cameraVC to dismiss.
[self performSelector:#selector(composeEmail) withObject:image afterDelay:1.0];
}
- (void) imagePickerControllerDidCancel:(UIImagePickerController *)picker
{
[[picker parentViewController] dismissViewControllerAnimated:YES completion:nil];
}
When a photo is taken and I choose the default "Use Photo" button I want to dismiss the camera ViewController and load the emailComposer View Controller, which uses this method:
- (void) composeEmail: (UIImage *)image {
NSString *bodyHeader = #"Here are you directions:";
NSString *mailBody = [NSString stringWithFormat:#"%#\n%#", bodyHeader, googleMapsURL];
MFMailComposeViewController *picker = [[MFMailComposeViewController alloc] init];
picker.mailComposeDelegate = self;
[picker setSubject:#"Google Maps Directions"];
[picker setMessageBody:mailBody isHTML:NO];
[picker setToRecipients:#[#"john.doe#gmail.com"]];
[picker setModalTransitionStyle:UIModalTransitionStyleCrossDissolve];
// Create NSData object as PNG image data from camera image
NSData *data = UIImagePNGRepresentation(image);
// Attach image data to the email
// 'DestinationImage.png' is file name that will be attached to the email
[picker addAttachmentData:data mimeType:#"image/png" fileName:#"DestinationImage"];
[self presentViewController:picker animated:YES completion:nil];
}
(I have left out some of the MessageUI details here but I have tested it and I know it is working)
The image taken should be passed to the emailComposer and attached as an email. When I build this on my device and tap the "Use Photo" button an error is thrown. The error message states "Attempt to present MFMailCompseViewController on ViewController whose view is not in the window hierarchy!" I am using only one ViewController and that VC contains one Image View.
Can anyone help me dismiss the camera and load the email composer?
Much appreciated!
First Dismiss the ImagePicker and then present ur mailcomposer will work then.U r dismissing the parent thta's y its not working [yourpicker dismissViewControllerAnimated:YES completion:nil];
- (void) imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
UIImage *image = [info objectForKey:#"UIImagePickerControllerOriginalImage"];
[yourpicker dismissViewControllerAnimated:YES completion:nil];
// Pass the image to email composer after dismissing the camera. Delay allowed for cameraVC to dismiss.
[self performSelector:#selector(composeEmail) withObject:image afterDelay:1.0];
}
To present view controller, use following :
[[[[[UIApplication sharedApplication] delegate] window] rootViewController] presentViewController: picker
animated:YES
completion:nil];
You can also look into this stackoverflow's question for further understanding
This question already has answers here:
Dismiss UIImagePickerController
(4 answers)
Closed 7 years ago.
Single View controller with single image view:
- (void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
if (self.imageView.image == nil) {
UIImagePickerController *imagePickerController = [[UIImagePickerController alloc] init];
imagePickerController.sourceType = UIImagePickerControllerSourceTypeCamera;
imagePickerController.modalPresentationStyle = UIModalPresentationCurrentContext;
imagePickerController.delegate = self;
[self presentViewController:imagePickerController animated:YES completion:nil];
}
else { }
}
- (void) imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
UIImage *image = [info objectForKey:#"UIImagePickerControllerOriginalImage"];
[picker dismissViewControllerAnimated:YES completion:nil];
[self performSelector:#selector(composeEmail:) withObject:image afterDelay:1.0];
}
- (void) imagePickerControllerDidCancel:(UIImagePickerController *)picker
{
[picker dismissViewControllerAnimated:YES completion:nil];
}
What follows is an MFMailComposer but the imagePicker does not dismiss after selecting 'use photo.' The imagePicker seems to dismiss and then reappear.
Here is a link to a Gist For the ViewController:
https://gist.github.com/FIDELHIMSELF/069609eb5489cf4723a1
I get two error warnings:
"Warning: Attempt to present on whose view is not in the window hierarchy!"
and
"Snapshotting a view that has not been rendered results in an empty snapshot. Ensure your view has been rendered at least once before snapshotting or snapshot after screen updates."
try dismissing the view controller like;
[picker dismissViewControllerAnimated:YES completion:nil];
So for example imagePickerControllerDidCancel delegate method would look like;
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker{
[picker dismissViewControllerAnimated:YES completion:nil];
}
I'm getting a black image picker preview. This DOES NOT happen if I delete the app then run it again. So the first time the app runs after being installed to my device it works. However if I bring up my image picker controller after that and capture an image, the preview is black. I have read all the answers mentioning background threading but I am not running any background threads. Im not sure what is causing this. It works perfectly the first time around but after that it never works.
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
//Image Picker settings
self.imagePicker = [[UIImagePickerController alloc] init];
self.imagePicker.delegate = self;
self.imagePicker.allowsEditing = NO;
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
self.imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
} else {
self.imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
}
self.imagePicker.mediaTypes = [UIImagePickerController availableMediaTypesForSourceType:self.imagePicker.sourceType];
[self presentViewController:self.imagePicker animated:NO completion:nil];
}
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
NSString *mediaType = [info objectForKey:UIImagePickerControllerMediaType];
if ([mediaType isEqualToString:(NSString *)kUTTypeImage]) {
//dismiss view controller
[self dismissViewControllerAnimated:YES completion:nil];
}
}
Don't present the image picker from the viewDidLoad method of your view controller. When viewDidLoad is being run, your view controller hasn't yet been added to the view controller hierarchy. You can try presenting it from viewDidAppear, and that might fix it.
I have two views. Very simple set up just to play around with the camera roll.
One view will bring up the camera roll using:
[self presentViewController:self.imagePicker animated:NO completion:nil];
which is triggered by a UIButton. It brings up the camera, everything's fine.
After taking a picture, I am calling the following to dismiss the controller:
[self dismissViewControllerAnimated:NO completion:nil];
Again, everything is working.
But the view that brings up the imagePicker Controller no longer receives touch (the UIButton will no longer brings up the camera again) after the Modal View is dismissed.
It will only start to receive touches again when I switch to another view and come back.
I have been searching for a solution to this problem but have not been successful in finding anything. Thanks in advance.
EDIT (Adding code):
In CameraController.m
This is where brings up the Camera Roll
(Subclass of UIViewController conforming to
<UIImagePickerControllerDelegate, UINavigationControllerDelegate>)
//UIButton that brings up the imagePicker
- (IBAction)useCamera
{
[self prepareImagePicker];
[self presentViewController:self.imagePicker animated:NO completion:nil];
}
//Initializing ImagePicker
- (void)prepareImagePicker
{
if ([UIImagePickerController isSourceTypeAvailable:
UIImagePickerControllerSourceTypeCamera])
{
self.imagePicker = [[UIImagePickerController alloc] init];
self.imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
self.imagePicker.mediaTypes = [NSArray arrayWithObjects:(NSString *) kUTTypeImage, nil];
self.imagePicker.delegate = self;
OverlayCameraView *cameraOverlay = [[OverlayCameraView alloc] initWithFrame:(CGRect){{0, 0}, 320, 480} andTheCameraController:self];
self.imagePicker.cameraOverlayView = cameraOverlay;
}
}
//Delegate Method when a picture is taken
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
self.imagePicker.delegate = nil;
[picker dismissViewControllerAnimated:NO completion:nil];
self.imagePicker = nil;
self.imageView.image = [info objectForKey:UIImagePickerControllerOriginalImage];
}
In OverlayCameraView.m
//Camera Overlay Class (Subclass of UIView)
- (id)initWithFrame:(CGRect)frame andTheCameraController:(CameraController*)cameraController
{
if ((self = [super initWithFrame:frame]))
{
self.camera = cameraController;
//.…2 UIButtons set up
}
return self;
}
//Overlay Cancel Button
- (void) cancel
{
[self.camera dismissViewControllerAnimated:NO completion:nil];
}
//Overlay Take Picture Button
- (void) takeAPicture
{
[self.camera.imagePicker takePicture];
}
You should be calling dismissViewControllerAnimated on the picker not self via the UIImagePickerControllerDelegate methods.
[picker dismissViewControllerAnimated:NO completion:nil];
or if you are keeping a reference to it:
[self.imagePicker dismissViewControllerAnimated:NO completion:nil];
EDIT:
Based on the revised code, I believe
self.imagePicker.cameraOverlayView = cameraOverlay;
should be:
self.imagePicker.cameraOverlayView = cameraOverlay.view;
Also this will cause a +2 reference count and will leak if you are not using ARC:
self.imagePicker = [[UIImagePickerController alloc] init];
It should be for proper reference counting:
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
self.imagePicker = picker;
[picker release];