I have a project that is a tab-bar controller. Each tab usually has a UINavigationController. The problem I have is this: I need a new tab with alot of navigation (roughly 30 navigation items grouped into 4-8 groups. Problem: My navigation bar is already full (can't use the navigation controller (or bar). What I need is navigation below the navigation bar (which has a global search bar and other global icons filling it). How can I implement this best?
What I have now: I have created a UIScrollView just under the navigation bar to serve as my "hand-rolled" navigation bar. It's a scrollView because I don't know (going forward) how many "groupings" of navigation items I will have (currently only 4). Each of these groups is represented by a UIButton, some of which should immediately present a view, and others which present a popover with further navigation items, which when selected will present a view.
Problem: I want a "content view" under my navigation view mentioned above, where I can present content based on the user's navigation choices. I have to support iOS 5.0, so I can't use the storyboard container view (unfortunately). I will have 3 types (maybe more later) of content views I will present, that I would like to create as individual view controllers and then push the appropriate one as it's selected in my navigation mentioned. Is there a 3rd party navigation controller I can use? Do I have to "roll my own"? Any advice would be greatly appreciated.
Here is a "slapped-together" picture of what I need to achieve:
I would make what you're calling the content view a subview of your main view, and use it as the view to which you will add a childViewController's view. If you haven't already read up on custom container controllers, you should do so, but the basic way of using them is like this.
The controller's whose view you show in your question would be the custom container controller. You could load up an initial controller in the viewDidLoad method, then switch the controller in your subview (I'm calling it self.containerView) in response to the user choosing something from your scroll bar:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
UIViewController *initial = [self.storyboard instantiateViewControllerWithIdentifier:#"InitialVC"];
[self addChildViewController:initial];
[initial.view.frame = self.containerView.bounds];
[self.containerView addSubview:initial.view];
self.currentController = initial;
}
-(void)switchToNewViewController:(UIViewController *) cont {
[self addChildViewController:cont];
cont.view.frame = self.containerView.bounds;
[self moveToNewController:cont ];
}
-(void)moveToNewController:(UIViewController *) newController {
[self.currentController willMoveToParentViewController:nil];
[self transitionFromViewController:self.currentController toViewController:newController duration:.6 options:UIViewAnimationOptionTransitionFlipFromLeft animations:^{}
completion:^(BOOL finished) {
[self.currentController removeFromParentViewController];
[newController didMoveToParentViewController:self];
self.currentController = newController;
}];
}
This should give you the basic idea. I took this from one of my test projects, so it will probably need a little tweaking.
Related
I am writing an application with help screens. As per my requirement I need to show the help screens when the view appears for the first time and I am placing the code on the tabbar controller class as (void)viewDidLoad:
{
[super viewDidLoad];
XDKWalkthroughController *sc = [[XDKWalkthroughController alloc]
initWithView:self.view];
[self addChildViewController:sc];
[self.view addSubview:sc.view];
sc.delegate = self;
[sc start];
}
When I am placing this code I am getting one more tabbar item along with existing tabbar item. How to avoid that in my case?
And same thing when I placed in the first view i.e in the first tab view controller view did class. Both navigation bar and tabbar are pushing the child view back.
I have tried these two scenarios, please help me with the possible solution.
I am trying to add custom UIViewController on top of everything but not covering full screen (basically popover), like this:
- (void) displayPopoverController: (UIViewController*) content;
{
[self addChildViewController:content];
content.view.frame = [self frameForContentController];
[self.view addSubview:content.view];
[content didMoveToParentViewController:self];
}
Everything works, but unfortunately it is underneath the navigation bar. So I decided to add UIViewController to the navigation controller like this:
- (void) displayPopoverController: (UIViewController*) content;
{
[self.navigationController addChildViewController:content];
content.view.frame = [self frameForContentController];
[self.navigationController.view addSubview:content.view];
[content didMoveToParentViewController:self.navigationController];
}
It worked, but there are 2 problems:
1) viewWillAppear is not called when I add popover (only viewDidLoad is called)
2) If I change orientation, my popover receives notification and adjusts to new orientation, but UIViewController behind it does not. It will only update its view after I remove popover.
Is there any way to fix 1 and 2? Maybe there is better approach(I don't want to use UIPopoverController with custom UIPopoverBackgroundView)?
IMO you should make a custom transition and present UIViewController modally.
You can get help on Custom UIViewController transition here : http://www.doubleencore.com/2013/09/ios-7-custom-transitions/
I am trying to add custom UIViewController on top of everything but not covering full screen
If you can confine yourself to iOS 7, your problems are over. You can use presentViewController: and a custom transition to do exactly what you are trying to do. This, in my view, is the most important new feature of iOS 7: you can present a view controller's view only partially covering the main interface.
See my book; for the particular example code from the book, see https://github.com/mattneub/Programming-iOS-Book-Examples/blob/master/bk2ch06p304customPresentedAnimation2/ch19p620customPresentedAnimation2/ViewController2.m
Plus I've now posted a single project at https://github.com/mattneub/custom-alert-view-iOS7. It shows how to make a view controller presented view that only partially covers the interface, plus it demonstrates that device rotation works correctly for all visible views (i.e. what's in front and what's visible behind).
this is my first question so please go easy!!
I have an iOS app that has 5 tab bars, each of which contains a Navigation controller. It seems that no matter where I call presentViewController:animated:completion from, I get no animation from the transition, the presented view controller just appears on screen!
This is also happening with my UIImagePickerController that I am presenting from one of my tabs. No presenting animation, but when i dismiss it it DOES animate away!
Here is a sample of the code, sent from a code generated tab bar button, with its action hooked up to a method which simply does this..
UserRegistrationViewController *userRegistration = [[UserRegistrationViewController alloc] init];
userRegistration.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentViewController:userRegistration animated:YES completion:nil];
If anyone has ANY ideas of things that I could try I would be most grateful!
I'm assuming that you want your animation to occur during the transition between tab bar presses. If so, you have little control over that animation, as the tab bar manages the transitions for you. It looks like you're trying to achieve a cross fade between tab presses. Although you really can't fade out the old view controller, you can easily make the new view controller fade in when it appears:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
//Set the view to transparent before it appears.
[self.view setAlpha:0.0f];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
//Make the view fade in. Set Opaque at the end for a performance boost.
[UIView animateWithDuration:0.5f
animations:^{
[self.view setAlpha:1.0f];
[self.view setOpaque:YES];
}];
}
Note that the tab bar is already presenting view controllers. You should not try to present the view controllers yourself. Let the tab bar manage this for you; that's what it's for.
I have a main view controller that lists a bunch of items, and when they tap on one of the items it segues them to the next view. However, in the next view, I don't want the navigation bar to be there, I only want it in the first view (I'm using a UIToolBar for the navigation bar, kind of like in iBooks).
How exactly do I go about achieving this? If I remove the main view controller from the navigation controller completely (unembedding, effectively) I can implement the nav bars selectively, but this solution doesn't allow segues, so it's no good.
My other solution was to call self.navigationController.navigationBarHidden = YES; in viewDidAppear for the second view, but with this, the UIToolBar that I added in my storyboard is pushed under the navigation bar that hasn't been hidden yet, and then when it does get hidden, it disappears and the UIToolBar "falls down", which is a pretty gross effect to the user.
What would be the best way to go about getting this effect?
The best way to do that is the following. In you viewWillAppear: in the first (rootViewController) of your UINavigationController, you set:
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.navigationController setNavigationBarHidden:NO animated:animated];
}
and then in you viewWillDisappear, you the the opposite:
-(void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[self.navigationController setNavigationBarHidden:YES animated:animated];
}
This way should work without nothing 'ugly' happening to the user.
NOTE:
Before reading this question please note that I have read the previous questions that explain the deficiencies regarding apple's implementation of UISplitViewController and how I should use the open-sourced "MGSplitViewController" because its not too easy to simply hide the master view controller on a split view controller in landscape-mode. Please keep in my mind that I'm limited to using the normal UISplitViewController in iOS 5.1.
Now onto the question:
I have a split view controller with table views on the left side (master view) and a detail view controller on the right. I'm using a navigation controller to control the left side which is a table view that transitions onto another table view ("DataTableViewController"). In order to hide this left side, I have placed a "hide" button on the navigation tool bar of the detail view controller. When the hide button is pressed, I change my "_hideMaster" property:
-(IBAction)hidePressed
{
_hideMaster = !_hideMaster;
// Must manually reset the delegate back to self in order to force call "shouldHideViewController"
self.splitViewController.delegate = nil;
self.spliteViewController.delegate = self;
}
and then automatically this method is called in the SplitViewController delegate:
// This is called when I change the delegate from nil back to self.
- (BOOL)splitViewController: (UISplitViewController*)svc shouldHideViewController: (UIViewController *)vc inOrientation:(UIInterfaceOrientation)orientation
{
return _hideMaster;
}
When I debug it, I can see that everything goes according to plan and the property has the correct value when it enters the method splitViewController:shouldHideViewController:inOrientation:
The only problem is that nothing happens. My left most table view (DataTableViewController) does not disappear. When I look closer, the (UIViewController *)vc parameter in the delegate method is not the table view controller that I want to hide but instead the navigation controller associated with this table view. So essentially it is trying to hide the navigation controller - which is clearly not what I want...
How can I make it so that the UIViewController parameter in the automatically called delegate method (shouldHideViewController:) calls the topmost view controller associated with that navigation controller? (After all, I want to hide DataTableViewController)
Here's how I handle it. Might need more work for making the MasterViewController reappear if it is not instantiated on the way back.
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.30f];
[[self.splitViewController.viewControllers lastObject] view].frame = self.splitViewController.view.frame;
[UIView commitAnimations];