Can you explain why this NavigationController setup works - iphone

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];
}

Related

Two UIViews for one ViewController

I'm not sure how to do this. So I originally had a ViewController that had one .xib, with one main view. I present it like this:
DogViewController *dvc = [[DogViewController alloc] initWithNibName:#"DogViewController" bundle:nil];
dvc.modalPresentationStyle = UIModalPresentationFormSheet;
dvc.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:dvc animated:YES];
[dvc release];
So that works fine. However now from a button press in the DogViewController.xib, I want to dismiss the current form sheet, and show another form sheet with some additional questions before proceeding. So I started by adding another view to in my original .xib of DogViewController, then got stuck in the logic of how to dismiss the first one, and show the second one. I'm assuming I need some outlet to the new view in the same .xib, but from there I'm lost. Thanks.
The way to do this would be to set it up with a UINavigationController as Mathiew mentions. However, if you really want to transition between two views on one view controller, you can refer to this sample code from Apple:
http://developer.apple.com/library/ios/#samplecode/ViewTransitions/Introduction/Intro.html
The code uses ImageViews to demonstrate the effect but I don't see why you can't use views instead :)
You can add a view within the other view in front of all of the other objects and just use its hidden property to control whether it's shown or not.
Why don't you use a navigation controller in your modal view, create another xib and do a [self.navigationController pushViewController:secondViewController animated:YES];
If you have a good reason, you can set a second view outlet secondView and use code like
UIView* superview = [self.view superview];
[self.view removeFromSuperView];
[superview addSubview:self.secondView];
Very simple solution is to hold reference to MainViewController and call methods on it that swap between two view controllers.
Like this:
#implementation MainViewController
- (void)showDogViewController {
[self dismissModalViewControllerAnimated:YES];
DogViewController *dvc = [[DogViewController alloc] initWithNibName:#"DogViewController" bundle:nil];
dvc.modalPresentationStyle = UIModalPresentationFormSheet;
dvc.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
dvc.mainViewController = self;
[self presentModalViewController:dvc animated:YES];
[dvc release];
}
- (void)showCatViewController {
[self dismissModalViewControllerAnimated:YES];
CatViewController *cvc = [[CatViewController alloc] initWithNibName:#"CatViewController" bundle:nil];
cvc.modalPresentationStyle = UIModalPresentationFormSheet;
cvc.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
cvc.mainViewController = self;
[self presentModalViewController:cvc animated:YES];
[dvc release];
}
}
#end
#implementation DogViewController
- (void)showCatViewController {
[mainViewController showCatViewController]
}
#end
#implementation CatViewController
- (void)showDogViewController {
[mainViewController showDogViewController]
}
#end

iphone loss of tabbar during uimodaltransition

Okay, working on a transition between a view with a tabbar and another view which is to be an information/about view. I have the code to transition from the view with tabbar and to transition back to previous view, but during the transition back I lose the tabbar at the bottom. Not sure exactly how to approach this with the tabbar in the MainWindow.xib
E.g.:
(IBAction)backButtonPressed:(id)sender
{
TablesViewController *tvc = [[TablesViewController alloc] initWithNibName:#"TablesView" bundle:nil];
tvc.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentModalViewController:tvc animated:YES];
[tvc release];
}
Thanks,
np
Try presenting the modal transition from the containing instance of UITabBarController and not the UIViewController the action was triggered from.
- (IBAction)backButtonPressed:(id)sender
{
TablesViewController *tvc = [[TablesViewController alloc] initWithNibName:#"TablesView" bundle:nil;
tvc.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self.tabBarController presentModalViewController:tvc animated:YES];
[tvc release];
}
I had the exact same problem, did a ugly solution:
- (IBAction)backButtonPressed:(id)sender {
[self.navigationController dismissModalViewControllerAnimated:YES];
}

ImagePicker in view hierarchy problem

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.

iPhone - Dismissing previous ModalViewControllerAnimated:YES then poping a new ModalViewControllerAnimated:YES - fail

I have a main window that pops a modal view controller. When done in this modal view controller, it returns to the main window then dismisses itself.
Then the main windows pops a new Modal view controller with animated=YES.
The problem is that the dismiss call that is done inside the first modalviewcontroller applies to both and SecondController is never shown.
Putting the first dismiss before or after the parent call does not change anything.
If first dismiss is set wih animate= NO, everything works fine. But I need the animation.
Main.m
- (void) entry {
FirstController *nextWindow = [[FirstController alloc] initWithNibName:#"theNIB" bundle:nil];
nextWindow.caller = self;
UINavigationController* navController = [[UINavigationController alloc] initWithRootViewController:nextWindow];
[self.navigationController presentModalViewController:navController animated:YES];
[nextWindow release];
[navController release];
}
- (void) thingsDoneInFirstModalController:(OBJECT)returnValue retval2:(OBJECT2)returnValue2 {
[self display2ndController];
}
- (void) display2ndController {
SecondController *nextWindow;
nextWindow = [[SecondController alloc] initWithNibName:#"NIB2" bundle:nil];
UINavigationController* navController = [[UINavigationController alloc] initWithRootViewController:nextWindow];
[self.navigationController presentModalViewController:navController animated:YES];
[navController release];
[nextWindow release];
}
1st ModalViewController.m
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[self.navigationController dismissModalViewControllerAnimated:YES];
[self.caller thingsDoneInFirstModalController:theResult retval2:someMoreResult];
}
What may I do ?
I don't want to catch anything in view....Disapear...
Why does the dismiss colides as they are not called from the same navigation controller ?
The reason is likely the animation when you dismiss it. Try showing the second modal window using the performSelector:withObject:afterDelay:, a method inherited from NSObject. Reference here.

presentModalViewController not working

here's my code:
ViewController *vc = [[ViewController alloc] initWithNibName:#"TableView" bundle:nil];
[self.navigationController presentModalViewController:vc animated:YES];
//[self setView:[vc view]];
If I call it, nothing happens. However, if I change it to:
ViewController *vc = [[ViewController alloc] initWithNibName:#"TableView" bundle:nil];
//[self.navigationController presentModalViewController:vc animated:YES];
[self setView:[vc view]];
The view appears just fine (without the transition, of course).
What am I doing wrong? Is there anything special you have to take care of when initializing the view controller? I tried to copy as much as possible from Apple's examples, but I can't get this to work...
Thanks for any input!
-- Ry
You can only present modal view controllers from controllers that have already been shown onscreen (usually through a UINavigationController or UITabBarController). Try creating a UINavigationController, pushing a viewController to it, and then presenting your modal controller. There's a starter project in Xcode that shows how to create a UINavigationController-based flow if you're unfamiliar with it.
One other thing to note: if you haven't pushed the view controller onto a UINavigationController, the .navigationController property will be nil, and messaging it will have no effect.
I encountered the same problem while attempting to show a modal view over another modal view. Ben's answer is correct, and can be implemented like so:
#interface FirstView: UIViewController {
UIViewController *firstView;
}
- (IBAction)showOptionsView:(id)sender;
#end
In the main view class:
- (void)viewDidLoad {
[super viewDidLoad];
firstView = [[UIViewController alloc]init];
[firstView setView:self.view];
[firstView setModalTransitionStyle:UIModalTransitionStyleCoverVertical];
}
- (IBAction)showOptionsView:(id)sender {
OptionsView *optView = [[OptionsView alloc]initWithNibName:#"OptionsView" bundle:nil];
if(firstView != nil) {
[firstView presentModalViewController:optView animated:YES];
[optView release];
}