I've spent ages stuck on this: Using the Tab Bar template (without storyboard) I can easily switch between tabs and switch between views within each table, however when it comes to swapping between a UITabBarController and a UIViewController whatever code i keep trying won't work.
-(IBAction)tabtoview:(id)sender{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
[UIView setAnimationTransition:UIViewAnimationTransitionCurlUp
forView:self.view
cache:YES];
[self.tabBarController removeFromParentViewController];
[self.view addSubview:self.mainscreen]; //Crashes here
[UIView commitAnimations];
}
Rather than removing the tabBarController it would be preferable if I could hide/disable it after having animated. Any help is appreciated thanks!
I think you problem is that UITabBarController and UINavigationController are those kind of controllers that cannot be handled the way you are doing.
You'd better subclass your UIWindow in app delegate and move the -(IBAction)tabtoview:(id)sender; method into the subclass of UIWindow. I tried and it works.
The reason is, you must have a controller to take the responsibility of switching views. What you are trying to do is, swapping controllers, rather than views. And that's a conflict. Tabs are part of UITabController, they are not views! It is also the same story for UINavigationController.
So, if you are simply swapping views, you can do it right in one of your viewControllers, but swpaping a controller with another (i.e. UIViewcontroller with UITabBarController) should be handled in a higher level, i.e. app delegate. The only instance available in that level is your UIWindow.
Why not using
UIView *v = [[UIView alloc] initWithFrame:[[UIApplication mainScreen] bounds]];
[self presentModalViewController:v animated:YES];
I think it should work
Related
Im writing a custom view controller container as per the iOS documentation on view controllers and i'm struggling on finding an elegant way to present the first view controller that also forwards the relevant display messages like viewWillAppear: automatically.
When i try transitionFromViewController:toViewController:duration:options:animations:completion: with the fromViewController: as nil i get an error. I have resorted to animating the view into the view hierarchy with a UIView animation block. This seems to break the automatic forwarding of the appearance methods and means its my responsibility to call viewWillAppear: and ViewDidAppear: at the appropriate times. Is there a more efficient way to transition the first view on to the screen that takes care of the appearance and rotation methods?
My code looks a little like this for animating in the first view controller.
self.visibleViewController = [[UIViewController alloc] init];
[self addChildViewController:self.visibleViewController];
[self.visibleViewController viewWillAppear:YES];
[self.visibleViewController.view setAlpha:0];
[self.view addSubview:self.visibleViewController.view];
[UIView animateWithDuration:0.5
delay:0
options:UIViewAnimationOptionCurveEaseOut
animations:^{
self.visibleViewController.view.alpha = 1;
}
completion:^(BOOL finished){
[self.visibleViewController viewDidAppear];
[self.visibleViewController didMoveToParentViewController:self];
}];
The answer was right there hidden in the documentation all along.
The documentation for UIViewController is
- (void)beginAppearanceTransition:(BOOL)isAppearing animated:(BOOL)animated
and the companion
- (void)endAppearanceTransition
Their documentation says never to call viewWillAppear and such from your own code. You can kick the chain off properly with these methods.
Are you sure the system doesn't send your child view controller the viewWillAppear/viewDidAppear/DidMoveToParentViewController messages? This bit of the Apple docs implies that it does:
In order for iOS to route events properly to child view controllers
and the views those controllers manage, your container view controller
must associate a child view controller with itself before adding the
child’s root view to the view hierarchy.
The way I read that, if you add a view controller as a child, then add the child's root view to your view, the system should send the appropriate messages as you add the view controller.
Try taking out your manual calls to those methods and set breakpoints in your child view controller to see if they still get called.
I am working with a navigation application. I have a homeViewController with two views(accept, service). When I click on a button in serviceView it should go to acceptView. I should have back button in navigation bar which takes me be back to serviceView from acceptView. When I am trying to use [self navigationController pushViewController, it only accepts viewcontroller but not view. Can any one please tell the alternative. Please help me.
Thanks in advance
You should have a different viewController for each view if you wish to use a navigationController properly.
Set up AcceptViewController and ServiceViewController separately. Then, from the AcceptViewController, you can create a ServiceViewController and push it onto the stack as follows:
-(void)showServiceView {
ServiceViewController *serviceViewController = [[ServiceViewController alloc] init];
[self.navigationController pushViewController:serviceViewController];
[serviceViewController release];
}
Assuming you've references to both acceptView and serviceView, you can just make this work by removing one as the subview and adding the other one as the subview of homeViewController's view. Something like,
[serviceView removeFromSuperview];
[self.view addSubview:acceptView];
for moving to acceptView. Switch them if you want to come back. However this mechanism will be abrupt. Use UIView's transitionFromView:toView:duration:options:completion: method to animate the transition. Something like,
[UIView transitionFromView:serviceView
toView:acceptView
duration:0.5f
options:UIViewAnimationOptionTransitionFlipFromLeft| UIViewAnimationOptionCurveEaseInOut
completion:NULL];
This will remove serviceView and add acceptView as the subview along with a transition to go by.
i coded in button action like
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:1.0];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:mainDelegate.window cache:NO];
[mainDelegate.window addSubview:[self.calcentryController view]];
[UIView commitAnimations];
it works fine,but when i use in calcentryController.m in one action
[self presentModalViewController:self.weeklyScoreController animated:YES];
to go another viewcontroller , it is not working any help pls?
Is there any reason you aren't using presentModalViewController for calcentryController? You can set modalTransitionStyle on calcentryController to UIModalTransitionStyleFlipHorizontal and just use presentModalViewController:animated instead of doing manual animations.
The reason this may help is because your code is not calling certain functions like viewWillAppear:, viewDidAppear:, etc., whereas presentModalViewController:animated calls all the right functions for presenting new views.
It's possible that your weeklyScoreController is nil. I'm not sure where you create it, since the code block is not pasted but that's a common mistake I see.
I could be because your code is in viewDidLoad instead of viewDidAppear as per presentModalViewController does nothing
I had the same issue.
If you have a deep hierarchy of view controllers' views subviewed into one another, then always try to present with immediately viewcontroller whose view is directly added to the window of ur iphone app.
For e.g. I had 4 levels of view like
window > vc1's view > vc2's view > vc3's view
So when I tried to call [vc3 presentModalViewController] it was not working..
I had to present with vc1 and it worked. I had vc1 referenced as a property to app delegate and hence was able to access easily.
But again, I didn't still find the actual reason, but I can say this worked for me.
Im new to iPhone development and I have really taken this to me. I love it, but there is one thing thats naggin' me. How do I keep switching view? I know how to come from first view that is given to me when I create a new project, to a view that I make, but how do I get passed this two windows? How do I get from to views that I created?
I have this app which have a main window with a NavigationController whih is feed with a UITableViewController. This is my main menu. I have a in the upper right corner, a "+"-button which gives me a new view, but how do I get a new view from here? How do I push a new view when the user pick something to add?
Hope someone understand my question. A link to some documentation would be fine. I have looked everywhere.
You can do this many diffrent way, you can do what the Sebastian said, you can also have a common RootViewController that manages your other view controllers view. This is what I like to do, I actually define a protocol on the RootViewController something like ToggleView:UIViewController newController UIViewController:oldController. I make any UIViewController that i want to be able to switch from that view to another implement this protocol. This makes since because generally when you click on a button, you know what View you want to go to next. So when a user clicks the button, in the UIViewController that owns the button i create the new ViewController whose view i want pushed into the screen, this is nice because it also allows me to set up data in the view controller and not have to delegate it to some other object or use a singleton to get the data in the new view, then i call my toggleView methods and the root view controller does the switching. I find this works pretty well and theres berely any code involved. I dont always u se this though, if I know a new view will always come out of another particular view, (for example a home page where one views events and creation of those events), in this case I will loosly couple the view controllers by using protocols.
For that particular situation, people usually use the presentModalViewController:animated: method of UIViewController. UINavigationController is a subclass of UIViewController, so your code would look something like this:
UIViewController *addingViewController = [[UIViewController alloc] initWithNibName:#"AddingView" bundle:nil];
[[self navigationController] presentModalViewController:addingViewController animated:YES];
[addingViewController release];
Here is the rootviewcontrollerdelegate definition
#protocol RootViewControllerViewDelegate
-(void)toggleView:(UIViewController )newController viewController:(UIViewController)oldController;
#end
a possible implementation to toggleView
-(void)toggleView:(UIViewController *)newController viewController:(UIViewController*)oldController {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:1];
[UIView setAnimationTransition:([oldController.view superview] ? UIViewAnimationTransitionFlipFromLeft : UIViewAnimationTransitionFlipFromLeft) forView:self.view cache:YES];
[newController viewWillAppear:YES];
[oldController viewWillDisappear:YES];
[oldController.view removeFromSuperview];
[self.view addSubview:newController.view];
[oldController viewDidDisappear:YES];
[newController viewDidAppear:YES];
[UIView commitAnimations];
[oldController release];
}
This will swipe the view controllers by flipping the view
Obviously you must make a new RootViewController somewhere and start with a view there, (could be the app delegate)
Now if you want a ViewController to be able to use the RootViewController it must conform to the protocol, you declare it in that classes interface like so
#interface MyViewController : UIViewController <RootViewControllerDelegate> {
id delegate;
}#property(assign) id <RootViewControllerViewDelegate> delegate;
Now you can use the delegates method to swap a view for another given that everything has been initialized right. the code to swap two controllers view could look like this
NewViewController *viewController=...
//you can set up your viewControllers data here if you need to
//Since its probable that this view has that data it can just set it instead of
//delegating
viewController.delegate=delegate; //setting up the RootViewController reference
[delegate toggleView:viewController viewController:self];
remember on the toggleView call back to release the old ViewController, if you dont youll get a leak since you lose all reference to that controller.
I'm slowly picking up Objective-C and the iPhoneSDK but I'm having some problems getting my head around the MVC pattern.
I'm fleshing out a game which I hope will have screens like a splash screen, title, help etc. What I'm currently doing is creating a new UIViewController and a new nib for each of these screens, is this the right practice? In the main AppDelegate I've created methods that show the views and add them with [window addSubView:controller.view]. What I'm finding is that with the show/hide code sat in the AppDelegate, I have to create a reference of the AppDelegate in the loaded controller in order to target the hide code.
This seems a bit awkward but I expect I'm probably approaching this wrong, how do you guys usually do this sort of thing?
// example from AppDelegate
-(IBAction)showHelp:(id)sender
{
helpScreen = [[helpController alloc] initWithNibName:#"helpView" bundle:nil];
// send copy of self in order to target closeHelp method from InterfaceBuilder
helpScreen.appDel = self;
helpScreen.view.alpha = 0;
[window addSubview:helpScreen.view];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:1.0];
helpScreen.view.alpha = 1.0;
[UIView commitAnimations];
}
Many Thanks,
UIViewController and a new nib for each of these screens, is this the right practice
Yeap!
[window addSubView:controller.view]
Are you also removing the old views at the end of the animation? You should be, otherwise you would have multiple view controllers running at once, something that you really don't want.
What I'm finding is that with the
show/hide code sat in the AppDelegate,
I have to create a reference of the
AppDelegate in the loaded controller
in order to target the hide code
Well somewhere you need the code that's responsible for switching views, and if the views can control this switching then they do need a way to trigger that. Rather than app delegate I usually have a RootViewController that performs these changes.
I tend to derive each of these views from a base class that has a delegate property for performing these changes. When the views need to change they call functions in the delegate. These are usually;
pushView - temporarily pushes the view as active, current view is removed from the view hierarchy but not destroyed. This would be used for something like a help screen.
popView - current view is destroyed and the previous view is reinstated. This is how the help screen would remove itself.
changeView - current view is destroyed and replaced with the specified view. This might be how you change from page1 to page2 of the help.
E.g.
// your root controller
-(void) changeView:(UIViewController) newController
{
newController = blah blah;
newController.delegate = self;
// add newController view, remove old one etc
}
// new controller
-(void) userPressedHelp
{
UIViewController* help = blah blah;
[self.delegate pushView: newController];
}
// help controller
-(void) userPressedOk
{
[self.delegate popView];
}
That seems reasonable to me. I'm pretty new to Obj-C but that's how I've done an application.
As long as the ViewControllers don't have knowledge of each other, I think you are doing just fine.