ImagePicker in view hierarchy problem - iphone

I can't figure out the most effective and "elegant" method for doing some task. The problem definition is:
I want to display several views, one of them is the ImagePicker with camera roll source.
The hierarchy looks similar to this:
MAIN VIEW ---> PICKER ---> IMAGE PROCESSING VIEW
When the user tap "back button" UI has to allow backward displaying.
I have tried several options:
1.
a) MAIN VIEW presents picker view modally.
b) In didFinishPickingMediaWithInfo delegate method dismiss picker modal view and after that invoke presentModalViewController with IMAGE PROCESSING VIEW.
Sample code:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
UIImage* pickedImage = [info valueForKey:UIImagePickerControllerEditedImage];
LastViewController* vc = [[LastViewController alloc] init];
vc.mainImage = pickedImage;
[self dismissModalViewControllerAnimated:NO];
[self presentModalViewController:vc animated:NO];
}
Problem is that, it doesn't works, cause controller can't display next modal after dismissing another (previouse won't disappear immediately, MAIN isn't active immediately, and can't present the new one).
2.
MAIN VIEW presents IMAGE PROCESSING VIEW modally, but immediately after that IMAGE PROCESSING VIEW is presenting picker view modally, waiting for done, dismissing picker and user can see IMAGE PROCESSING VIEW with image from library.
Sample code:
in some action of main view controller:
ImageProcessViewController *vc = [[ImageProcessViewController alloc] initWithNibName:#"ImageProcessViewController" bundle:nil];
vc.delegate = self;
vc.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
[self presentModalViewController:vc animated:NO];
[vc release];
in ImageProcessViewController:
- (void)viewDidLoad {
[super viewDidLoad];
//some UI init here
if(self.sourceType == UIImagePickerControllerSourceTypePhotoLibrary) {
UIImagePickerController *ipc = [[UIImagePickerController alloc] init];
ipc.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
ipc.delegate = self;
ipc.allowsEditing = YES;
[self presentModalViewController:ipc animated:NO];
[ipc release];
}
}
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
UIImage* pickedImage = [info valueForKey:UIImagePickerControllerEditedImage];
self.mainImage = pickedImage;
[self dismissModalViewControllerAnimated:NO];
}
Problem is that, i can't call presentModalViewController in viewDidLoad method because it won't work (it is too early in view controller live cycle I guess). I tried also in viewDidAppear, but in that case I have to set some ivar flag, to display picker view only once and empty IMAGE PROCESSING VIEW is displayed for short time before image picker view and i don't want this.
3.
I tried to figure out how to use Navigation Controller to do this, beacause UIImagePickerController is using his nav controller, but this is private structure and documentation says programmers can't do that.
Please give me some suggestions because I really lost my way at the moment

In your main view controller, use viewDidAppear:animated: - this will be called when the modal transition has finished. You can safely start another modal transition from there.

Related

Can you explain why this NavigationController setup works

I'm trying to understand how to setup a NavigationController. I don't understand why this code works with both a pushViewController AND presentModalViewController. I thought it had to be one or the other.
For context, this is a UIViewController that creates a UIImagePickerController. There are two view controllers after, the first (EditPictureViewController) edits the image itself and the second edits the properties. Believe I should use presentModalViewController.
...also is there a way to not dismiss the Modal View Controller so I can have a retake picture button on the EditPictureViewController?
Thanks.
- (void)viewDidLoad {
[super viewDidLoad];
self.navController = [[UINavigationController alloc] init]; }
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
[self dismissModalViewControllerAnimated:NO];
EditPictureViewController *viewController = [[EditPictureViewController alloc] initWithImage:image];
[viewController setModalTransitionStyle:UIModalTransitionStyleCrossDissolve];
[self.navController setModalTransitionStyle:UIModalTransitionStyleCrossDissolve];
[self.navController pushViewController:viewController animated:NO];
[self presentModalViewController:self.navController animated:YES]; }
This pushes the EditPictureViewController onto the NavigationController's view stack.
[self.navController pushViewController:viewController animated:NO];
Then you present the NavigationController here:
[self presentModalViewController:self.navController animated:YES];
I mean, all you're doing is presenting a modal view from a view controller and that modal happens to be a NavigationController.
The setup you have is not the "normal way it's done. The standard paradigm would be to create the navigation controller in the didFinishPickingMediaWithInfo: method, and set its root view controller to viewController, rather than pushing it. You normally think of "pushing" as moving to the next controller, whereas what you're doing is really just setting the root view controller in a non-standard way. Also you should be using the current methods for presenting and dismissing modal view controllers -- the ones you're using are depreciated. I'm not sure you need to set both of those transition styles either. Try commenting one out, and see if it still works.
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
[self dismissViewControllerAnimated:NO completion:nil];
EditPictureViewController *viewController = [[EditPictureViewController alloc] initWithImage:image];
self.navController = [[UINavigationController alloc] initWithRootViewController:viewController];
[viewController setModalTransitionStyle:UIModalTransitionStyleCrossDissolve];
[self.navController setModalTransitionStyle:UIModalTransitionStyleCrossDissolve];
[self presentViewController:self.navController animated:YES completion:nil];
}

dismissModalViewAnimated actually removes parent view

I have an application that allows a user to add a picture to a log.
If the user chooses to add from library, everything is fine, but if a user chooses to take
a picture with the camera there's an issue:
When the camera modal view is animated in and I either take a picture and tap on "Use" or i click on the "Cancel" button, the view I'm in when calling dismissModalViewAnimated is removed from its superview.
Anyone got an explanation for this?
Here's the code I use for presenting the modal viewcontroller
pickerCont = [[UIImagePickerController alloc] init];
pickerCont.delegate = self;
pickerCont.sourceType = UIImagePickerControllerSourceTypeCamera;
[self presentModalViewController:pickerCont animated:YES];
And this is what i use to dismiss it:
[self dismissModalViewControllerAnimated:YES]
Actually you are dissmissing parentview. here self represents parentView
Use UIImagePickerController's delegate to dissmiss UIImagePickerController
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
//get picked image here
[pickerCont dismissModalViewControllerAnimated:YES]
}

Driving UIImagePickerController from UITabBarController

Here's my goal:
I'd like to show the UIImagePickerController from a TabBarController and once the photo is taken, I want the "Use" button to take me another view controller.
My problem:
I have MainCameraTabController which inherits from UIViewController and serves as the class that orchestrates the launching of UIImagePickerController and the picker's delegate. When the picker is finished, I try to launch another a different ViewController from MainCameraTabController but I get the error,
*** Assertion failure in -[UIWindowController transition:fromViewController:toViewController:target:didEndSelector:
If I put a timed delay between when the UIImagePickerController is dismissed and when I launch the next controller, it works okay but I'd like to do this more elegantly.
Is there a better way to structure my class inheritance so that I can have MainCameraTabController display the Picker and then a 2nd view controller?
// #
// # 1. Create the tab bar and add the MainCameraTabController:
// #
// tab1Controller and tab3Controller are also created
cameraTabController = [[MainCameraTabController alloc] init];
tabBarController = [[UITabBarController alloc] init];
NSArray *tabViewControllers = [NSArray arrayWithObjects:tab1Controller,
cameraTabController
tab3Controller, nil];
tabBarController.viewControllers = tabViewControllers;
self.window.rootViewController = self.tabBarController;
// #
// # 2. MainCameraTabController interface & implementation
// #
#interface MainCameraTabController : UIViewController <UINavigationControllerDelegate, UIImagePickerControllerDelegate>
{
}
- (void)showCamera;
#end
#implementation MainCameraTabController
// #
// # 3. Show the camera when the view loads
// #
- (void)viewDidLoad
{
[self startCameraController:self usingDelegate:self];
}
- (void)showNextController
{
FollowupController *fc = [[FollowupController alloc] initWithNibName:#"SomeView" bundle:nil];
// THIS IS THE PROBLEM
[self presentModalViewController:cameraPicker animated: YES];
}
- (BOOL)startCameraController:(UIViewController *)controller
usingDelegate:(id <UIImagePickerControllerDelegate, UINavigationControllerDelegate>)pickerDelegate
{
UIImagePickerController *cameraPicker = [[UIImagePickerController alloc] init];
// configure the cameraPicker
// #
// # Apple's doc specifies that UIImagePickerController must be launched with
// # presentModalViewController
// #
[controller presentModalViewController:cameraPicker animated: YES];
}
// UIImagePickerControllerDelegate method called when photo taking is finished
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
// work to handle the photo
// Dismiss the picker
[[picker parentViewController] dismissModalViewControllerAnimated: YES];
[picker release];
[self showNextController];
}
#end
And on a related note, I checked to see what the picker's parentViewController is when
imagePickerController:didFinishPickingMediaWithInfo
is invoked and the parent is not MainCameraTabController but instead UITabBarController. Not sure why this is the case.
Because of the animation when dismissing the view, you need delay for the animation to finish before it can execute the next animation. You can solve this by setting the animated to NO. This will cut the animation and execute the next one immediately.
For the views, i had the similar experience, what i did was to switch the sequence of the views. I launched the view that i want to show after the picker first, in the viewDidload method, i created and display the picker so after the picker is dismissed, it will show the view that i want. If you want to make them look natural you could always play with the hidden property of the view to smoothen the flow.

How to switch views when Iphone camera returns?

I am new to Iphone development. I am working on an application which involves two views. I have a camera button in view one which opens up the default Iphone camera. This is achieved by having this code in the IBAction for camera button in ViewOneController:
UIImagePickerController *picker =
[[UIImagePickerController alloc] init];
picker.delegate = self;
picker.allowsEditing = NO;
picker.sourceType = UIImagePickerControllerSourceTypeCamera;
[self presentModalViewController:picker animated:YES];
[picker release];
The view controller for the first view is also the UIImagePickerControllerDelegate for the camera. When the picture is clicked and the camera view returns to the function imagePickerController:didFinishPickingWithMediaInfo where I do this:
(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
[picker dismissModalViewControllerAnimated:YES];
[self presentModalViewController:ViewTwoViewController animated:YES];
}
So basically all I am trying to achieve is from viewone click "take picture" ---> Open camera --> after camera is done jump to view two. Quite simmilar to what it is in the flickr app. However after I take the picture from camera my app returns to view one and view two is not shown. What am I missing here?
Also from a conceptual perspective I guess IOS keeps a stack of views for any app. When presentModalViewController is called the view is shown and it is added to the stack and when dismissModalViewController is called the view is removed from the stack and the parent view is show. Is that right?
Thanks.
You probably need to put the call to [self presentModalViewController:ViewTwoViewController animated:YES] in viewWillAppear which will be called after the picker view has been removed.
You probably also need to surround the call with some check to only present viewTwo when applicable.

UIImagePickerController reloads view after its dismissed?

I create the picker:
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
imagePicker.delegate = self;
imagePicker.allowsEditing = NO;
[self presentModalViewController:imagePicker animated:YES];
and I handle the didFinishPickingMediaWithInfo:
- (void) imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
[picker dismissModalViewControllerAnimated:YES];
[picker release];}
but this calls the viewDidLoad on self. This is not normal is it? Whats wrong?
Your app probably received a memory warning, which caused all view controllers who are not displayed on screen to unload their views. This is quite normal while you are in the image picker because the camera needs a lot of memory. The moment you dismiss the image picker your view controller reloads its view.
As this is perfectly normal behavior, your app must deal with this situation correctly.
I had a similar issue with this, I was displaying a popup during a long press gesture. It appeared as though the modal was not dismissed after the image was selected. However, the long press gesture event gets called several times, so a new popup was being displayed for every event. In my gesture handler I do something like this as to fix:
if (![imagePickerPopoverController isPopoverVisible]){
//show pop-up etc
}
I had some kind of that issue and I'd tried to set presentation "Over full screen" and it worked without reloading