I have a ViewController, VC1a, that presents VC2:
VC1a -> presentViewController: VC2
Is it possible to change VC1a into VC1b so that when dissmissViewControllerAnimated is called, it animates to VC1b instead of VC1a?
The reason I ask is because I want to return to a different screen without it animating back to VC1a. This relates to portrait/landscape changes.
Warning. This is potentially a bad/confusing UI choice for your users. But if you must...
You may be able to put VC1a inside a UINavigationController and modify the navigation stack while VC2 is in the foreground. Something like:
// in VC1a.m
[self presentViewController:VC2 animated:YES completion:^{
NSMutableArray *navigationStack = [[NSMutableArray alloc] init];
for (UIViewController *viewController in self.navigationController.viewControllers)
{
if (viewController != self.navigationController.viewControllers.lastItem)
{
[navigationStack addObject:viewController];
}
else
{
VC1b *viewControllerToSwapIn = [[VC1b alloc] init];
// probably some more initialization here
[navigationStack addObject:viewControllerToSwapIn];
}
}
self.navigationController.viewControllers = navigationStack;
}];
or possibly a better idea:
// in VC1a.m
[self presentViewController:VC2 animated:YES completion:^{
VC1b *viewControllerToSwapIn = [[VC1b alloc] init];
// probably some more initialization here
[navigationStack addObject:viewControllerToSwapIn];
[self.navigationController popViewControllerAnimated:NO];
[self.navigationController pushViewController:viewControllerToSwapIn animated:NO];
}];
OK, I implemented a Container view controller with two children - one for portrait, one for landscape and this took care of my problem.
I have spent days trying to figure out how to handle rotation correctly within iOS6 and I didn't realise there was a bug in rotating UITableViewController when pushed from a UINavigationController.
Thanks for the response #paulrehkugler - I was getting pretty desperate when I asked this question. There just doesn't seem to be any good examples of how to handle orientation changes while UINav/TableViewControllers are presented from a main view. I certainly wasn't wanting to implement such a hack.
Related
The app I'm making utilizes multiple views. such as a disclaimer view, a view to display answer so on and so forth.Up until now this is the code that I've been using to switch from one view to another
-(IBAction)swichtogain:(id)sender{
gainview *second = [[gainview alloc]initWithNibName:nil bundle:nil];
[self presentModalViewController:second animated:YES];
[second release];
}
I found this method in a tutorial, I was wondering, is this the best way to do it ? I use the same code to switch back n forth from one view to another for eg.
-(IBAction)swichtoview1:(id)sender{
view1 *view = [[gainview alloc]initWithNibName:nil bundle:nil];
[self presentModalViewController:view animated:YES];
[view release];
}
and when in view1 if the user hits the back button the following code gets executed
-(IBAction)swichtomainview:(id)sender{
mainview *view = [[gainview alloc]initWithNibName:nil bundle:nil];
[self presentModalViewController:view animated:YES];
[view release];
}
I haven't edited anything in the appdelegate files and this is a view based app. Does this method cause it to use more memory ? During the activity monitor test using the instruments , I noticed the memory usage gets higher every time I go from the main menu to another view and back to the main menu !. Is there a better way than this ?. Also one of the view is a calculator so when the user hits the calculate button it switches to the next view while changing the textfield to the answer, below is the code for that !
-(IBAction)calculate{
MyClass *setnum = [[MyClass alloc]init];
setnum.grade_num = grade;
setnum.stage_num = stage;
setnum.ex_lym = ex_ly;
setnum.pos_lym = pos_ly;
setnum.er_num = er;
setnum.noderatio = pos_ly/ex_ly;
if(text1.text.length <=0 ||text2.text.length <=0||text3.text.length<=0||text4.text.length<=0||text5.text.length <=0){
UIActionSheet *action = [[UIActionSheet alloc]initWithTitle:#"Incomplete Values" delegate:self cancelButtonTitle:#"Ok" destructiveButtonTitle:nil otherButtonTitles:nil];
[action showInView:self.view];
[action release];
}else{
answer *ans =[[answer alloc]initWithNibName:nil bundle:nil];
[self presentModalViewController:ans animated:YES];
float i = calc_gain(setnum.grade_num, setnum.noderatio, setnum.stage_num, setnum.er_num);
NSString *result = [NSString stringWithFormat:#"%f",i];
ans.answer1.text = result;
ans.bar.hidden = NO;
[ans release];
}
[setnum release];
}
You should consider using one of the provided container view controllers (UITabBarController, UINavigationBarController or UISplitViewController on the iPad and so on).
The way you use presentModalViewController is most likely the wrong way. For one, calling presentModalViewController will retain your views. Keeping allocating new controllers and displaying their views via presentModalView is therefore increasing your memory footprint with each navigation step.
In general, a viewcontroller which shows another modal viewcontroller is also responsible for dismissing it again. The way to dismiss a modal view controller is therefore to let the presented controller inform its parent through delegation and ask the parent to dismiss (often on tapping a 'done' button).
I'm not even sure whether stacking modalViewControllers is a supported scenario, but at least didn't find anything stated otherwise in the documentation.
Asked here yesterday:
Switching views for iphone application - is this the right way?
I think another good way to go about this is to do this and add a univanigationcontroller:
[self.navigationController pushViewController:second animated:YES];
I have some view controller which I call with the following method:
myViewController *myView = [[myViewController alloc] initWithNibName:nil bundle:nil];
myView.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentModalViewController:myView animated:YES];
[myView release];
if I use the app a few times I get a memory warning and the app freezes for a few seconds! I think the reason is that i switch the view but not discharged the old one !!?!!?!!
(i set my outlets to nil and release them)
how can I unload the old view after switching to the new one?
Thanks in advance
When switching the view be sure to call dismissModalViewController:(BOOL)animated on myViewController.
In the class that launch the modalViewController you could make a property for the modal viewcontroller which you retain. Then you could write something like this.
//This would be in an action or something...
if (self.myViewControllerProperty == nil) {
self.myViewControllerProperty = [[[MyViewController alloc] initWithNibName:nil bundle:nil] autorelease];
}
[self presentModalViewController:self.myViewControllerProperty animated:YES];
Then instead of setting the
myView.modalTransitionStyle =
UIModalTransitionStyleCoverVertical;
Move that code to the modalViewController and write self.modalTransitionStyle = UIModalTransitionStyleCoverVertical; I think that looks cleaner, keep the configuration of each viewcontroller separted don't mix it up.
And as the maclema said, call dissmissModalViewController, but you probably are doing that...
Could be any number of problems but you don't need to (and can't) unload the old view. Make sure you are releasing objects and setting outlets to nil in viewDidUnload of all of your view controllers. viewDidUnload will be called when a memory warning occurs so if you don't handle it correctly you'll have leaks and can crash. Other than that, hard to know what else your app is doing that is contributing to the crash.
I have an issue, viewWillAppear method in the UIViewController which is added to the screen by presentModalViewController method does not "go into" viewWillAppear method. Only time this method is invoked is together with the viewDidLoad, the first time.
- (IBAction)openModal:(id)sender {
if (self.nvc == nil) {
ModalViewController *vc = [[ModalViewController alloc] init];
self.nvc = vc;
[vc release];
}
self.nvc.segmentedIndex = [[self.navigationController.viewControllers objectAtIndex:0] index];
[self presentModalViewController:self.nvc animated:YES];
}
The property is of type retain.
Thanks in advance.
right, it works different and it now goes into viewWillAppear only once. So if you want to change the appearance of your view after dismissing a modal view you should do it using a modal delegate pattern. See the link:
http://useyourloaf.com/blog/2010/5/3/ipad-modal-view-controllers.html
Though it's for iPad, but you can get the idea. In the latest iOS versions it works the same.
Hope it helps
I'm searching a way to be able to display one modal view controller after another one, and make the second appear while the first is disapearing.
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.
I planned to do that this way, but the problem is that the dismiss call that is done inside the first modalviewcontroller applies to both and SecondController is never shown.
I don't understand why because each modal view has its own navigationcontrollers, so they shouldn't collide.
I tried another way by showing the second modal view with a NSTimer after 0.5 sec, but it's not satisfying : the second appears when the first has completely disapeared. Not smooth at all... If I set the delay less than 0.5 sec, the second modal view never shows up. And using such a timer to make this does not seem to be a good way of coding.
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];
}
Do you know a way to make this possible (make the second view appears while the first one is disappearing), with some code for example ?
Thank you.
Try creating some dummy ViewController, and present your second one using it.
I need to display a couple of view controllers (eg, login screen, registration screen etc). What's the best way to bring each screen up?
Currently for each screen that I'd like to display, I call a different method in the app delegate like this:
Code:
- (void) registerScreen
{
RegistrationViewController *reg = [[RegistrationViewController alloc] initWithNibName:#"RegistrationViewController" bundle:nil];
[window addSubview:reg.view];
}
- (void) LoginScreen
{
LoginViewController *log = [[LoginViewController alloc] initWithNibName:#"LoginViewController" bundle:nil];
[window addSubview:log.view];
}
It works, but I cant imagine it being the best way.
I'd recommend reading the View Controller Programming Guide if you haven't: http://developer.apple.com/iphone/library/featuredarticles/ViewControllerPGforiPhoneOS/Introduction/Introduction.html
It sounds like presenting a view controller modally may be your best bet - but you'll probably want to wrap it in an UINavigationController first.
eg
UINavigationController *navController = [[[UINavigationController alloc] initWithRootViewController:theControllerYouWantToPresent] autorelease];
[self presentModalViewController:navController animated:YES];
I've often wondered if this is the best way myself, but when I'm not using IB's built-in stuff (like a NavigationController) I have a single method in the AppDelegate, switchToViewController:(UIViewController *)viewController that I pass...well, it's pretty self-explanatory I guess. This way there's only one place where it's done, and I can easily define transitions in that method once the app nears completion.
Also, don't forget to remove the previous views in your methods, otherwise you're liable to run out of memory. Something like this:
-(void) switchToViewController:(UIViewController *)c {
if(c == currentController) return;
[currentController.view removeFromSuperview];
[window addSubview:c.view];
[currentController release];
currentController = [c retain];
}