I had to have a tabBar with 9 tabs, so I added a Srollview(MHScrollViewController) with 9 buttons instead of tabBar. On click of each button, I add a viewController as subview to the Srollview.
In AppDelegate, have the following code:
MHScrollViewController *scrollViewController = [[MHScrollViewController alloc] initWithNibName:#"MHScrollView" bundle:nil];
scrollViewController.managedObjectContext = [self managedObjectContext];
self.navigationController = [[UINavigationController alloc] initWithRootViewController:scrollViewController];
self.window.rootViewController = self.navigationController;
Now say for one tab (button), I have added MHBikesViewController to MHScrollViewController as subView. In MHScrollViewController , I do this
bikesViewController = [[MHBikesViewController alloc] initWithNibName:#"MHBikesView" bundle:nil];
bikesViewController.managedObjectContext = self.managedObjectContext;
bikesViewController.view.frame = baseViewiPhone.frame;
CGRect theFrame = bikesViewController.view.frame;
theFrame.origin.y = 0;
bikesViewController.view.frame = theFrame;
bikesViewController.navigationController = self.navigationController;
[baseViewiPhone addSubview:bikesViewController.view];
Now, I have two buttons on the MHBikesViewController page. When clicked, I want to push a new viewcontroller on MHBikesViewController. I am able to push, but the scrollView gets hidden under this viewcontroller.
UINavigationController will cover all its contents with newly pushed controller anyway, so you need to take your scrollview with buttons outside of navigationcontroller.
Beware of UIViewController parent/child relationships & responsabilities when designing UI.
A controller holds a main UIView, and all its subviews.
When adding this viewController's view into a more complex view hierarchy, this controller should then be the child of the viewController controlling this 'containement' UI.
Ask yourself : what IS your model for containment ?
9 tabs and some related content that occupy the rest of the screen?
Then in your case, MHScrollViewController is the daddy, it holds scrollable tabs and current viewController main view. It shouldn't be UINavigationController (which can be himself parent 'content' holding your MHBikesViewController)
Parent->Child containement in your case:
MHScrollViewController -> UINavigationController -> MHBikesViewController
Adding and removing child viewController is responsibility of the parent.
//(somewhere in MHScrollViewController.m or .h )
#property (nonatomic, strong) UIViewController *newContentController;
#property (nonatomic, weak) UIScrollView *tabsScrollView;
// method for pushing any 'tab' controller
// might be your UINavigationController
- (void)displayTabController:(UIViewController *)vc
{
// remove previous controller
if (self.contentController) {
[self.contentController.view removeFromSuperview];
[self.contentController removeFromParentViewController];
}
//push the new controller, maintaining child/parent relationship
self.contentController = newContentController;
[self.view addSubview:contentController.view];
[self.contentController didMoveToParentViewController:self];
// set frame of contentController so that it stays above scrollView
self.contentController.frame = CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height - self.tabsScrollView.bounds.size.height)
}
You can have a tab bar with 9 tabs the standard way. It will automatically create a "more" tab. It might not be as slick as you wanted.
Related
I've a UIViewController which loads it's view form a Xib file. In my AppDelegate.m I would like to initiate my rootViewController with that myViewController and I would like that the title of the navigtionItem is set by taking the NavigationBar view which is part of the Xib file of the myViewController:
MyViewController *myViewController = [[MyViewController alloc] init];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:myViewController];
According to the documentation
Each time the top-level view controller changes, the navigation controller updates the navigation bar accordingly.
In my setup this seems not to happen or I haven't indicated that my NavigationBar view is actually the navigationBar to consider.
How can I tell the NavigationController to update it's navigationItem content (title, left and right bar buttons) according the NavigationBar view which is part of the Xib file from myViewController?
Update
My Xib layout looks like this:
I know I can set those items in code by:
self.navigationItem.titleView = ...;
self.navigationItem.leftBarButtonItem = ...;
But I want them do design in the Xib file of the ViewController and they should be used in the NavigationController.
In ViewWillAppear method in your ViewController set-
self.navigationItem.title = #"Title name";
Also in the same way you can set self.navigationItem.leftBarButton and RightBarButton items
Adding a UINavigationBar view to the main UIView doesn't do what you think it does. It merely adds a navigation bar view there in the view, it does not tie into the UINavigationController.
If you use a storyboard, you can add the UINavigationItem as a child of the UIViewController. But since you are not using a storyboard, the easiest way to do it is to update the navigationItem in viewDidLoad.
Sidenote: Apple does not recommend using viewDidLoad to setup the navigation item. If you really want to do it the proper way, you can for example do it in the navigationItem getter.
- (UINavigationItem*)navigationItem
{
// get super navigation item
UINavigationItem *navItem = [super navigationItem];
// do stuff
return navItem;
}
To give some context, I have logic that programmatically decides what view controller to insert into the navigation controller. For example:
If(true){
MyViewController * MyObject = [[MyViewController alloc]init];
myNavigationController = [[UINavigationController alloc]initWithViewController:MyObject];
else {
MyOtherViewController * MyOtherObject = [[MyViewController alloc]init];
myNavigationController = [[UINavigationController alloc]initWithViewController:MyOtherObject];
}
self.tabBarController.viewControllers=[NSArray arrayWithObjects:myNavigationController,nil];
Hopefully that illustrates my point of how I insert views inside of navigation controller. Now onto my problem:
I have an action listener with a button inside of "MyViewController" that essentially replaces the navigation/tab bar index when the user clicks the button. Is it possible to update a navigation/tab bar index with just a button?
MyViewController.m
- (IBAction)MyActionListener:(id)sender {
MyOtherViewController *MyOtherObject = [[MyOtherViewController alloc] initWithNibName:#"MyOtherViewController" bundle:nil];
[self.view insertSubview:MyOtherViewController.view atIndex:2];
}
When I do this, I get a crash EXEC_BAD_ACCESS I'm just wondering if my implementation/approach is wrong. I noticed this question: Update UITabBar Views?
However, doesn't seem to fit the results I am looking for. Hopefully I am clear. Thanks!
Yes it is possible to switch your views on button click with navigation.
You currently in VC1 , you have other two vc VC2 & VC3 and on button click you choose VC2 or VC3 but you did not change the VC1 place.
Recently, I am working on a project which have multiple ViewControllers, the controllers's view hierarchy need to display on screen at same time, the link below(it is a picture) is my design.
http://www.lazycatdesign.com/stuff/question.png
MainViewController is a Container ViewController, I add the MenuViewController and PictureViewController to it like this:
// Create the controllers
MainViewContorller* mainVC = [[MainViewController alloc] init];
MenuViewController* menuVC = [[MenuViewController alloc] init];
PictureViewController* pictureVC = [[PictureViewController alloc] init];
// add MenuViewController to MainViewController as its child controller
[mainVC addChildViewController:menuVC];
[mainVC.view addSubview:menuVC.view];
[menuVC didMoveToParentViewController:mainVC];
// add PictureViewController to MainViewController as its child controller
[mainVC addChildViewController:pictureVC];
[mainVC.view addSubview:pictureVC.view];
[pictureVC didMoveToParentViewController:mainVC];
Menu View and Picture View is now displayed on screen, the problem is only the Picture View can response the UI Event(such as the Tap Gesture). It seems only the last view hierarchy I add to Container ViewController can response UI Event, why? and what is the correct way to display multiple ViewController's view hierarchy in a Container ViewContorler?
Finally, the problem is solved, as rdelmar said, I forget to set the frames to the subviews, apple's document View Controller Programming Guide for iOS (page 117) also mention this, the codes should be:
// Create the controllers
MainViewContorller* mainVC = [[MainViewController alloc] init];
MenuViewController* menuVC = [[MenuViewController alloc] init];
PictureViewController* pictureVC = [[PictureViewController alloc] init];
// add MenuViewController to MainViewController as its child controller
[mainVC addChildViewController:menuVC];
[menuVC setFrame:frameOfMenuView]; // set the correct frame to menu view
[mainVC.view addSubview:menuVC.view]; // add menu view as sub view to main view
[menuVC didMoveToParentViewController:mainVC];
// add PictureViewController to MainViewController as its child controller
[mainVC addChildViewController:pictureVC];
[pictureVC setFrame:frameOfPictureView]; // set the correct frame to picture view
[mainVC.view addSubview:pictureVC.view]; // add picture view as sub view to main view
[pictureVC didMoveToParentViewController:mainVC];
When I try to push a UIViewController subclass (MissionViewController) onto a UINavigationController from within my root view controller, the viewDidLoad method is only called if I reference the underlying view after initializing the view controller. However, even with the method called, the screen is not updated.
Both the view controller and the navigation controller are not nil. The file owner in MissionView.xib is set to MissionViewController. The view property of the file owner points to the nib view. I've verified that the topViewController property of the navigation controller points to the MissionViewController object.
If I change MissionViewController to be the root view controller, the view loads fine. Saw several similar posts but still having problems.
rootViewController.h
#interface TreeGraphController : UIViewController
{
MissionViewController *missionViewCtrlr;
}
#property(nonatomic, retain) MissionViewController *missionViewCtrlr;
rootViewController.m
#import "MissionViewController.h"
...
if (!missionViewCtrlr)
{
MissionViewController *ctrlr = [[MissionViewController alloc] initWithNibName:#"MissionView" bundle:nil];
ctrlr.view.hidden = NO;
self.missionViewCtrlr = ctrlr;
[ctrlr release];
}
myAppDelegate *del = [[UIApplication sharedApplication] delegate];
[del.navigationController pushViewController:missionViewCtrlr animated:NO];
What about using
[self.navigationController pushViewController:missionViewCtrlr];
in the rootViewController? I assume rootViewController has been pushed to a UINavigationController and that the navigation controller's view was added as a subview of self.window in the app delegate?
Btw, you may simplify part of your code by just saying
if(!missionViewCtrlr)
self.missionViewCtrlr = [[MisionViewController alloc] init...];
Hi i have a UITabBarController with 5 tabBar items.
The forth is UIScrollView.
The area that presented by the forth tab i wont to have specific height.
so till here i've done this
This is were i create my UITabBarController.(aViewController.h)
#interface aViewController: UIViewController <UITabBarControllerDelegate>{
UITabBarController *newTabBarController;
UIView *myView;
}
aViewController.m
- (void) viewDidLoad{
newTabBarController = [[UITabBarController alloc]init];
newTabBarController.delegate = self;
myView = [[UIView alloc]initWithFrame:CGRectMake(0,0,320,self.view.frame.size.height - newTabBarController.tabBar.frame.size.height)];
NSArray *controllers = [NSArray arrayWithObjects:myView, nil];
newTabBarController.viewControllers = controllers; //this is the line that a get an error :Tread1:Program receive signal: SIGABRT
[myView release];
}
if i make a viewController subclass of UIViewController with Xcode and put it in the NSArray there is no problem but i want my view has screen.height - tabbar.height so i tryed make one programmatically.
Any help apresiated!
List item
UIView size
You can do this via Interface Builder.
Create the View you want for a given tab. Then go into the Attribute Inspector. The tab named "simulated metric" allow you to setup a TabBar (and even a NavigationBar).
SIGABRT
myView = [[UIView alloc]initWithFrame:CGRectMake(0,0,320,self.view.frame.size.height - newTabBarController.tabBar.frame.size.height)];
NSArray *controllers = [NSArray arrayWithObjects:myView, nil];
newTabBarController.viewControllers = controllers; //this is the line that a get an error :Tread1:Program receive signal: SIGABRT
This property is called viewControllers, not views.
The NSArray must contain UIViewController instances, or subclasses.
Thus, it better to define your View with IB (and configure look and feel to display TabBar, etc).
Then create your UIViewController with the method initWithNibName:bundle:, and put these instance into the newTabBarController.viewControllers.
Hope it helps