My iPhone app is tab bar-based, but I would like to fire an action which switches out the tab bar controller view completely and replaces everything in the window with a view from a different XIB file. I would guess this has to be done in the application delegate (since this is the "chief" class), but I don't know the right way to go from there. Does anyone know how to do what I am trying to do?
Thanks in advance!
Your tab view controller could have it's action method, such as -(IBAction)onChangeView and that method calls a method on the [[UIApplication sharedApplicaton] delegate], such as -(void)toggleScreen.
-(IBAction)onChangeView:(id)sender
{
MyAppDelegate *delegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
[delegate toggleScreen];
}
Then in your app delegate method do something like this:
-(void)toggleScreen
{
[[[window subviews] objectAtIndex:0] removeFromSuperview];
[window addSubview:otherView];
}
It may be different if you need transitions, however.
You don't really have to go all the way to the app delegate. You can easily remove your existing views and controllers and add new views. It really does depend on what you are doing. You could, for example, temporarily put aside the existing view structure and go with something totally different, and get back to the original scheme if you want (I'm not sure of the user experience though).
In my apps, I usually have a root view controller or I use my main window to add views to and remove views from. Some views will add other views to themselves or transition another view onto the rootview or main window. Some views close themselves to reveal the view below. The options are limitless, and depend on your needs and architecture.
Thanks guys! Nick, that's just the code I needed. In case anyone finds this handy, here's the code I used to add animation to switch the view. Just put this in a method in the app delegate:
AnotherViewController *anotherViewController = [[AnotherViewController alloc] initWithNibName:#"AnotherView" bundle:nil];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:1.0];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:self.window cache:YES];
[[[window subviews] objectAtIndex:0] removeFromSuperview];
[window addSubview:[anotherViewController view]];
[UIView commitAnimations];
Related
I have an issue with changing my orientation on certain pages in my app. The shouldAutoRotatefunction does not fire on any one page. I have done some digging and hoping someone can tell me if this code is right.
I have a window, a Navigation Controller called homepageController, and a Tab Bar Controller named mainController. The app works as follows. I present the homepageController for the user to log in. Once the correct login key is entered I remove my homepageController view from the window and add the mainController view. Here is the code
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.6];
[UIView setAnimationDelegate:self];
[UIView setAnimationTransition:UIViewAnimationTransitionCurlUp forView:appDel.homePageController.view.superview cache:NO];
[appDel.homePageController.view removeFromSuperview];
[UIView commitAnimations];
[appDel.window addSubview:appDel.mainController.view];
[appDel.mainController setSelectedIndex:0];
[appDel.window bringSubviewToFront:appDel.mainController.view];
I go to my first page on the tab bar and try to rotate it, with a breakpoint on shouldAutoRotate, but it never fires.
Again I did some digging and found that my shouldAutoRotate method in my .m file for homepageController gets triggered anytime I change orientations. I looked at my xib file and this is what I have.
I saw that my homepageController is the rootViewController and when switching from tab to tab on the mainController I am using this code.
-(void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController{
UINavigationController *nav = (UINavigationController *) viewController;
[nav popToRootViewControllerAnimated:NO];
}
So seeing that my homepageController is the rootViewController that is why shouldAutoRotate always gets called there.
I am wondering if there is a better solution to this. I don't think Im doing this right at all so any guidance would be great.
Thank you
I think shouldAutoRotate is not calling because you are using addSubView: like
[appDel.window addSubView: appDel.mainController]
Set your viewcontrollers as rootviewControllers everywhere you have used as addSubview in window.
So use
appDel.window.rootViewController= appDel.mainController;
May be now shouldAutoRotate will fire event.
Hope it works for you.
I am trying to create an animation for switching views on iOS devices.
I have create an application with three views and I have some navigation buttons.
The way I use to switch views is this:
-(IBAction) loadThirdView:(id)sender {
[self clearView];
self.thirdViewController.view.frame = CGRectMake(0, 208, 160, 208);
[self.view insertSubview:thirdViewController.view atIndex:0];
}
As you can see this is the action that takes place once I press the button. What I would like is the new view to appear in an animated way.
Specifically I want it to start from the left hand side of the screen and slide to the right. I do not want it just to appear.
Is this possible? how can I do it?
Oh no! Ah, no! Please do not display UIViewControllers this way.
Present your UIViewController this way:
[self presentModalViewController:self.thirdViewController animated:YES]
Before presenting it, you can change the modalTransitionStyle property of the view controller to suit your needs.
If using a UINavigationController, use instead:
[yourNavController pushModalViewController:self.thirdViewController animated:YES]
This is a nice little article (if not a little too harsh): Abusing UIViewControllers
To animate it the way you specifically would like (as the UINavigationController style is sliding in from the right), you might want to use something like what is proposed in this SO question: iPhone Pushing View Controller in a left direction
You can try
[UIView transitionFromView:currView toView:nextView duration:0.5f options:UIViewAnimationOptionTransitionFlipFromLeft completion:nil];
if you want different type of animation. There're lots AnimationsOptions you can choose, just set the options:.
Sample Code :
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationDuration:0.6];
yourImageVieew.alpha=0.9;//insert here what you want
[UIView commitAnimations];
I'm getting frustrated at this.
I want to create an iPhone application to show a list of events, one day for each 'screen'. I want a bar at the top with 'next' and 'prev' buttons that allow me to go to tomorrow or yesterday.
It is not a UINavigationController style navigation, because navigation is not hierarchical. Therefore I don't think I should use the pushViewController: method, as many examples and tutorials suggest.
I think that the appdelegate class should remove the current view and create a new viewcontroller and view and add it to the window. However I can't manage to get it working. Also I would like nice transitions.
Can someone point to a code sample that I can look at?
Thank you.
P.D. My question is similar to this one but there is no useful answer.
I wouldn't get hung up on the view controller so much. The view controller/view duality can sometimes get in the way of building custom interfaces.
What you need is a UIToolbar with two buttons, and a sorted array of UIView objects configured appropriately for your entities.
Then when the buttons are clicked, simple [UIVIew animations] should get the job done.
I'm not going to write the code for you. Any casual analysis of the build in UIView animation components will point you on your way.
The only real thing I can tell you is that, having built sophisticated interfaces for the iPhone, the biggest learning curve is knowing when and when not to use UIViewController as opposed to UIView. This is tricky because most of the standard apple components use Controller.
Now it works. Just some details were missing. I'll leave the answer here so that other people can comment on it or use it.
In the AppDelegate class I added this method:
-(void) navigateToDay:(NSDate*) newDay fromDay:(NSDate*) currentDay
{
UIViewAnimationTransition transition = ([newDay compare:currentDay]<0)? UIViewAnimationTransitionCurlDown :
UIViewAnimationTransitionCurlUp;
SequentialNavigationViewController* newController = [[SequentialNavigationViewController alloc] initWithNibName:#"SequentialNavigationViewController" bundle:nil];
newController.app = self;
newController.currentDay = newDay;
[newController.view setFrame:[[UIScreen mainScreen] applicationFrame]];
[UIView beginAnimations:#"transition" context:NULL];
[UIView setAnimationDuration:0.50];
[UIView setAnimationTransition:transition forView:self.window cache:YES];
[window addSubview:newController.view];
[self.viewController.view removeFromSuperview];
[UIView commitAnimations];
self.viewController = newController;
[newController release];
}
And I call this method from the SequentialNavigationViewController prevButtonClicked and nextButtonClicked methods.
Not so hard after all!
i am new to iphone application development.
I have a mainmenu view controller, which has a login button.
once i click the login button i display the next login view controller by calling this
LoginController *lc2=[[LoginController alloc] initWithNibName:#"LoginController" bundle:nil];
UINavigationController *navigationController = [[UINavigationController alloc]initWithRootViewController:lc2];
[self presentModalViewController:navigationController animated:YES];
But this view appears to come from the right side of the screen,i want to provide the effects like, curl or flip,when i navigate from one view controller to another.
Please help me with the code to provide this effect
Check the Metronome example from Apple's SDK. Its a bit too much code for posting it right here, hence I would like to point you to that example.
The basic idea is using a parent view-controller that handles the transitions between two or more child view-controllers. That involves setting up a protocol for smoothly allowing the child-view-controllers to inform the root-view-controller about transitions to do. Bit vague, I know - so please jump into the example code.
Perhaps something like this, separating the animation code from the modal view controller's presentation code:
LoginController *lc2=[[LoginController alloc] initWithNibName:#"LoginController" bundle:nil];
UINavigationController *navigationController =
[[UINavigationController alloc]initWithRootViewController:lc2];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.75];
[UIView setAnimationDelegate:self];
[UIView setAnimationTransition: UIViewAnimationTransitionFlipFromRight forView:navigationController.view cache:YES];
[self presentModalViewController:navigationController animated: NO];
[UIView commitAnimations];
I quite agree with luvieere, except I think that the view specified in
[UIView setAnimationTransition: UIViewAnimationTransitionFlipFromRight forView:navigationController.view cache:YES];
must be the container view, in wich a subview will be added or removed, and I'm not sure if navigationController.view is the container view. I would try with different combinations, including self.view, self.view.superview (that depends of the behavior of "presentModalViewController").
I have a View that has a UIWebView, and an OptionsPane (Custom UIViewController with Custom view).
I want when the view is shown, for the options pane (located on the top of the main view) to FLIP into place. I am using the code, and I am getting a strange result.
The FIRST time the view is shown, the options pane seems to already be visible... When I hit BACK on my navController, and pull up the View again, the animation works perfectly.
Can anyone shed some light on this topic?
- (void)viewDidLoad {
[super viewDidLoad];
optionsPane=[[OptionsPaneController alloc] initWithNibName:#"OptionsPane" bundle:nil];
}
- (void)viewWillAppear:(BOOL)animated {
[optionsPane.view removeFromSuperview];
[self checkOptionsVisible];
}
-(void)checkOptionsVisible{
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.5];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:[optionsPane view] cache:YES];
[[self view] addSubview:[optionsPane view]];
[theWebView setFrame:CGRectMake(0,87,320,230)];
[[optionsPane view] setFrame:CGRectMake(0,0,320,87)];
[UIView commitAnimations];
}
Hmm, I don't think the viewWillAppear message is getting sent the first time. There are two things that I read in the SDK. You should call super inside that message and there is a big warning that may apply to your first time:
Warning: If the view belonging to a view controller is added to a view hierarchy directly, the view controller will not receive this message. If you insert or add a view to the view hierarchy, and it has a view controller, you should send the associated view controller this message directly. Failing to send the view controller this message will prevent any associated animation from being displayed.
Ultimately, I would run through the debugger and make sure that viewWillAppear message is being sent when you think it is.
If I understand what your explaining, I had a very similar problem the other day.
What happening on the first load is that viewDidLoad fires first. loading the nib file takes a bit more time than it takes for the viewWillAppear to fire itself.
What we're getting is a nib loads after the viewWillApper already retired.
On any load after that, the viewDidLoad will not fire, letting the viewWillAppear to do its loyal flipping job.
What to do?
First, try to change your code to use "viewDidAppear". That should help, but you have to see if it looks good.
Another option (ugly one, I know) is to have a call to checkOptionsVisible on the viewDidLoad too.
If non of that help, I would consider a timer as a hack - if the requirements allow it.
I hope that make you closer to solve the problem.
Updated for your situation:
Instead have four views:
A backing view
The main View
The back view (options pane) 100 pixels
The front view (blank view) 100 pixels
Add the main view to the backing view as normal.
Add the front view to the backing view where you would like the options pane to appear.
make sure the front and back view have the same frame.
Use the same code as below using the methods flip the front and back views.
Original Answer
You need 3 views:
A backing view
The front View
The back view
The backing view just holds the other 2 as they flip back and forth Below are the flipping methods. I place them both in backingViewController:
- (void)displayBack{
//parent controller is an ivar so the sub-view controllers know who their daddy is
backController.parentController = self;
[UIView beginAnimations:nil context:#"flipTransitionToBack"];
[UIView setAnimationDuration:1.2];
//note self.view IS the backing view
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:self.view cache:YES];
//remove the front view
[[frontController view] removeFromSuperview];
//add the back view view
[self.view addSubview:[backController view]];
[UIView commitAnimations];
//giving a heads up to the view that is about to come on screen
[backController viewWillAppear:YES];
}
- (void)displayFront{
[UIView beginAnimations:nil context:#"flipTransitionToFront"];
[UIView setAnimationDuration:1.2];
[UIView setAnimationDelegate:self];
//I'm interested in knowing this has happened
[UIView setAnimationDidStopSelector:#selector(flipAnimationDidEndWithID:finished:context:)];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:self.view cache:YES];
//remove back view
[[backController view] removeFromSuperview];
//add the front view
[self.view addSubview:[frontController view]];
[UIView commitAnimations];
}
The view property on a UIViewController is lazily-loaded -- even when you're init-ing with a nib as you are here, the view itself doesn't actually get instantiated until the first time the property is accessed.
It's hard to know exactly what's happening without seeing more code, but you may get the results you want if you access optionsPane.view in viewDidLoad (you don't need to do anything with it, just access the property to force loading).