When I click the tab bar that holds my kal calendar the calendar disappears:
This is my code in viewWillAppear:
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
KalViewController *calendar = [[KalViewController alloc] init];
[self.navigationController pushViewController:calendar animated:YES];
calendar.dataSource = self;
calendar.delegate = self;
[calendar reloadData];
self.tabBarController.delegate = self;
}
I also have this method:
-(void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController
{
[self viewWillAppear:YES];
//Even when I comment out this line the problem stays!
}
If you need more infomation just ask.
EDIT:
You are using your tab bar controller improperly. Indeed, you should populate it with your controllers (either in Interface Builder or by setting the tab bar controller's controllers property) and let it do its job.
On another coin, note that viewWillAppear can be called multiple times, so this is the last place where you want to allocate a new controller.
If you have overridden viewWillAppear in order for your controller to show something when it s view is displayed that is not the correct approach.
EDIT:
If you create your UI programmatically, these are the steps you should follow in you application:didFinishLaunching: to setup the rootViewController:
FirstViewController *fistVC = ...
SecondViewController *secondVC = ...
ThirdViewController *thirdVC = ...
NSArray *viewControllers = [[NSArray alloc] initWithObjects:fistVC, secondVC, thirdVC, nil];
self.tabController = [[UITabBarController alloc] init];
[self.tabController setViewControllers:viewControllers animated:YES];
self.window.rootViewController = self.tabController;
If you build your UI in Interface Builder, you will do the same graphically, but I cannot reproduce it here.
In any case, I hope this snippet clarifies the way the tab bar controller works: you instantiate all of its controllers, put them in an array, pass the array to the tab bar controller. No need to instantiate anymore the tabbed controllers (neither in viewWillAppear nor in viewDidLoad)...
Related
For my code structure:
On AppDelegate, I declared 4 UINavigationController with their own root UIViewController for my UITabBar.
I created one custom UIViewController as template, in where my other UIViewControllers are sub-class.
On my template:
I have my rightBarButtonItem to show current user profile.
// public method added on template
- (void) goToProfile {
NSLog(#"going through...");
ProfileViewController *ctrl = [[ProfileViewController alloc] init];
[self.navigationController pushViewController:ctrl animated:YES];
}
For my leftBarButtonItem:
- (void) goBack {
[self.navigationController popViewControllerAnimated:YES];
}
First click on the rightBarButtonItem, works fine. If I click the leftBarButtonItem to go back then re-click the rightBarButtonItem, it won't work anymore.
In addition, I have a button on one of my UIViewController that is calling the public method goToProfile. And that works fine.
I got help from my co-worker. The approach is something similar to #Vidhyanand900 answer. I hope this will help others in the future.
tabbarSelectedIndex = 1; // profile tab index
ProfileViewController *ctrl = [[ProfileViewController alloc] init];
UINavigationController *navController = [_appDelegate.mainTabBarController.viewControllers objectAtIndex:tabbarSelectedIndex];
[navController pushViewController:ctrl animated:YES];
self.mainTabBarController.selectedIndex = tabbarSelectedIndex;
If you are pushing or popping with UINavigation controllers of UITabBar
Else show UINavigation Controllers inside UITab Bar..i.e; Is Profile View controller is part of UITab bar or not..
Then you need to change the index of tab bar as below
self.tabBarController.selectedIndex=0;//if profile is first tab
ProfileViewController *ctrl = [[ProfileViewController alloc] init];
[self.navigationController pushViewController:ctrl animated:YES];
Hope it helps you...
I am showing custom tab bar using tab bar controller.
And Creating Separate navigationController for view controllers.
First *firstViewController = [[First alloc]init];
UINavigationController *firstNavController = [[UINavigationController alloc]initWithRootViewController:firstViewController];
Second *secondViewController = [[Second alloc]init];
UINavigationController *secondNavController = [[UINavigationController alloc]initWithRootViewController:secondViewController];
Third *thirdViewController = [[Third alloc]init];
UINavigationController *thirdNavController = [[UINavigationController alloc]initWithRootViewController:thirdViewController];
tabBar.viewControllers = [[NSArray alloc] initWithObjects:firstNavController, secondNavController, thirdNavController, nil];
tabBar.delegate=self;
tabBar.selectedIndex=0;
but when i am trying to pop to root on tab click, Only 3rd navigation controller is accessible.
So its working for only 3rd tab, First and second is not working.
If you're loading a view controller on top of a tabBarController this is how you would dismiss your loaded view controller.
[self.presentingViewController dismissViewControllerAnimated:self completion:nil];
UINavigationController * navController = (UINavigationController *) [[[tabbarcontroller viewControllers] objectAtIndex: tabbarcontroller.selectedIndex] rootViewController];
If you want all those viewcontrollers to be popped, you may find this delegate useful.
- (BOOL)tabBarController:(UITabBarController *)tabBarController
shouldSelectViewController:(UIViewController *)viewController {
//iterate though tabbar-viewcontrollers to pop all of them
//return NO, if you want this to be handled like an action
return NO;
//return YES, if you want this to be handled like a normal selection
return YES;
}
Hope it helps
It will pop to rootViewController when tap on the tab.
-(BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController{
[(UINavigationController*)viewController popToRootViewControllerAnimated:YES];
return YES;
}
I have an app with an "old" Tabbarcontroller and a MainWindow.xib. I have to delete the tabbarcontroller logic to transform the app and made a "Left side menu" type, like facebook. I have a problem, i have alredy created the left side menĂ¹ with a tableviewcontroller and i can open,close and push correctly my controllers... Now i want to insert a different customnavigation bar class each navigation controller (in the old version of the app each navigation controller had his custom navigation class to change che image in relation with the active viewcontroller). This is the code i use in the tableview didselect method of a row in my left side menu:
if (indexPath.row==1) {
DemoViewController *demoController = [[DemoViewController alloc] init];
UINavigationController *navigationController = self.menuContainerViewController.centerViewController;
[navigationController setValue:[[CustomNavigationBar alloc]init] forKeyPath:#"navigationBar"];
NSArray *controllers = [NSArray arrayWithObject:demoController];
navigationController.viewControllers = controllers;
[self.menuContainerViewController setMenuState:MFSideMenuStateClosed];
}
this code manage correctly the slide and load correctly the viewcontroller inside MFSideMenu. The custom navigationbar class is assigned but not works correctly:
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated{
this method is never called, maybe MFSideMenu overwrites the uinavigationcontroller delegate? How i can do to made "active" again this navigation controller delegate method?
found a solution,this code:
DemoViewController *demoController = [[DemoViewController alloc] init];
UINavigationController *navigationController = self.menuContainerViewController.centerViewController;
CustomNavigationBar *navClass=[[CustomNavigationBar alloc]init];
[navigationController setValue:navClass forKeyPath:#"navigationBar"];
[navigationController setDelegate:navClass];
NSArray *controllers = [NSArray arrayWithObject:demoController];
navigationController.viewControllers = controllers;
[self.menuContainerViewController setMenuState:MFSideMenuStateClosed];
instead of:
DemoViewController *demoController = [[DemoViewController alloc] init];
UINavigationController *navigationController = self.menuContainerViewController.centerViewController;
[navigationController setValue:[[CustomNavigationBar alloc]init] forKeyPath:#"navigationBar"];
NSArray *controllers = [NSArray arrayWithObject:demoController];
navigationController.viewControllers = controllers;
[self.menuContainerViewController setMenuState:MFSideMenuStateClosed];
In this way the delegate is assigned correctly...
For an iPhone app how can I create a tab view programmatically, preferably in Objective-C?
It's quite simple to create a UITabBar via the UITabBarController. The following example should work within your AppDelegate class.
App Delegate Interface
Firstly, within the interface, we'll define our UITabBarController.
UITabBarController *tabBarController;
App Delegate Implementation
Then, within the implementation file's application:didFinishLaunchingWithOptions: method, we'll then initialise our tab bar controller.
// Initialise our tab bar controller
UITabBarController *tabBarController = [[UITabBarController alloc] init];
Next, you need to create the view controllers that you want to add to the tab bar controller. We'll need to add some information into these to set the tab's title/icon, but I'll come back to that at the end.
// Create your various view controllers
UIViewController *testVC = [[TestViewController alloc] init];
UIViewController *otherVC = [[OtherViewController alloc] init];
UIViewController *configVC = [[ConfigViewController alloc] init];
As the setViewControllers:animated: method requires an array of view controllers, we'll add our view controllers to an array and then release them. (As the NSarray will retain them.)
// Put them in an array
NSArray *viewControllers = [NSArray arrayWithObjects:testVC, otherVC, configVC, nil];
[testVC release];
[otherVC release];
[configVC release];
Then simply provide the UITabBarController with the array of view controllers and add it to our window.
// Attach them to the tab bar controller
[tabBarController setViewControllers:viewControllers animated:NO];
// Put the tabBarController's view on the window.
[window addSubview:[tabBarController view]];
Finally, make sure you call [tabBarController release]; within your dealloc method.
View Controller Implementation
Inside each of your view controllers, you'll also want to set the title and icon for the tab within the init method as follows:
// Create our tab bar item
UITabBarItem *tabBarItem = [self tabBarItem];
UIImage *tabBarImage = [UIImage imageNamed:#"YOUR_IMAGE_NAME.png"];
[tabBarItem setImage:tabBarImage];
[tabBarItem setTitle:#"YOUR TITLE"];
This is how we have to create tabbar programmatically
UINavigationController *BandNavigationController3;
AudienceSettingsViewController *audienceSettingsViewView =[[AudienceSettingsViewController alloc]initWithNibName:#"AudienceSettingsViewController" bundle:nil];
BandNavigationController3 = [[UINavigationController alloc]initWithRootViewController:audienceSettingsViewView];
BandNavigationController3.tabBarItem.title = #"Settings";
BandNavigationController3.tabBarItem.image = [UIImage imageNamed:#"settings.png"];
[BandNavigationController3.tabBarItem initWithTabBarSystemItem:UITabBarSystemItemFavorites tag:4];
BandNavigationController3.navigationBar.hidden = YES;
[bandTabBarArray addObject:BandNavigationController3];
[BandNavigationController3 release];
[audienceSettingsViewView release];
[tabBarController setViewControllers:bandTabBarArray];
[bandTabBarArray release];
I am in kind of situation that I need to start with a tab based application and in that I need a split view for one or more tabs. But it seems that split view controller object can not be added to the tabbarController. (Although tabbar object can be added to the splitviewcontroller).
The problem can be seen otherways: I have a full screen in the left part I have a table view when any row is selected in the table a popover should come out pointing that row. Now when any row in the popover is selected the rows in this popover comes to the left under the selected row (only this row would be visible) and another popover comes out from the selected row. (Breadcrumb navigation type)
I think I am clear in what I explained. So guys any ideas or work arounds?
Please let me know if I am not clear in my question.
Thanks,
Madhup
Using the interface builder, create a split view controller and a tab bar controller and link them to your outlets:
#property (nonatomic, retain) IBOutlet UITabBarController *tabBarController;
#property (nonatomic, retain) IBOutlet UISplitViewController *splitViewController;
In your app delegate didFinishLaunchingWithOption, assign your split view controller to the tab bar controller:
splitViewController.tabBarItem = [[[UITabBarItem alloc] initWithTitle:#"Title" image:nil tag:0] autorelease];
NSArray *controllers = [NSArray arrayWithObjects:splitViewController, /* other controllers go here */ nil];
tabBarController.viewControllers = controllers;
[window addSubview:tabBarController.view];
[window makeKeyAndVisible];
This will create a tab bar controller (with only 1 tab in this case), which is displayed correctly in all orientations.
I've written up a subclass for the UISplitViewController that will listen for changes to device orientation and orient itself accordingly. With this class, I can now place split views within a UITabBarController and each split view will behave correctly upon rotation, even if it's not the frontmost tab. I've successfully deployed this in TexLege and it was approved for use in the App Store, but your mileage may vary. Please see the repository at Github.
Feel free to fork and modify it, and I'm always interested in hearing comments (or complaints) about it. https://github.com/grgcombs/IntelligentSplitViewController
I made a sample application. and found we can do it programmatically like:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSMutableArray *array = [NSMutableArray array];
NSMutableArray *tabArray = [NSMutableArray array];
UISplitViewController *splitViewConntroller = [[UISplitViewController alloc] init];
MainViewController *viewCont = [[MainViewController alloc] initWithNibName:#"MainViewController" bundle:nil];
[array addObject:viewCont];
[viewCont release];
viewCont = [[DetailViewController alloc] initWithNibName:#"DetailViewController" bundle:nil];
[array addObject:viewCont];
[viewCont release];
[splitViewConntroller setViewControllers:array];
[tabArray addObject:splitViewConntroller];
[splitViewConntroller release];
array = [NSMutableArray array];
splitViewConntroller = [[UISplitViewController alloc] init];
viewCont = [[MainViewController alloc] initWithNibName:#"MainViewController" bundle:nil];
[array addObject:viewCont];
[viewCont release];
viewCont = [[DetailViewController alloc] initWithNibName:#"DetailViewController" bundle:nil];
[array addObject:viewCont];
[viewCont release];
[splitViewConntroller setViewControllers:array];
[tabArray addObject:splitViewConntroller];
[splitViewConntroller release];
// Add the tab bar controller's current view as a subview of the window
[tabBarController setViewControllers:tabArray];
[window addSubview:tabBarController.view];
[window makeKeyAndVisible];
return YES;
}
Hope this helps.
To let a tabbarcontroller appear as a master view for splitviewcontroller you should rewrite tabbarcontroller so that it will support or orientations(so say, using a category for the class UITabBarController)
See my post about retrofitting split view controllers to an existing tab bar interface: http://markivsblog.blogspot.com/2010/04/retrofitting-ipad-uisplitviewcontroller.html
I created a UITabBarController subclass which properly propagates the rotation messages to all UISplitViewControllers it contains. This maintains the correct internal state of the UISplitViewControllers. However, one of the SplitViewController delegate methods is not called if the SplitViewController is not visible, so I account for this in the detail view controller viewWillAppear method. I've confirmed this works in iOS5.0 - iOS6.1
OSTabBarController.m
#import "OSTabBarController.h"
#implementation OSTabBarController
-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration{
[super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
for(UIViewController *targetController in self.viewControllers){
if(targetController != self.selectedViewController && [targetController isKindOfClass:[UISplitViewController class]]){
[targetController willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
}
}
}
-(void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation{
[super didRotateFromInterfaceOrientation:fromInterfaceOrientation];
for(UIViewController *targetController in self.viewControllers){
if(targetController != self.selectedViewController && [targetController isKindOfClass:[UISplitViewController class]]){
[targetController didRotateFromInterfaceOrientation:fromInterfaceOrientation];
}
}
}
#end
DetailViewController
#implementation OSDetailViewController
-(void)viewWillAppear:(BOOL)animated{
//the splitViewController:willHideViewController:withBarButtonItem:forPopoverController: may not have been called
if(!UIInterfaceOrientationIsPortrait(self.interfaceOrientation)){
self.navigationItem.leftBarButtonItem = nil;
}
}
#pragma mark - UISplitViewControllerDelegate Methods
- (void)splitViewController:(UISplitViewController *)splitController willHideViewController:(UIViewController *)viewController withBarButtonItem:(UIBarButtonItem *)barButtonItem forPopoverController:(UIPopoverController *)popoverController
{
[self.navigationItem setLeftBarButtonItem:barButtonItem animated:YES];
}
- (void)splitViewController:(UISplitViewController *)splitController willShowViewController:(UIViewController *)viewController invalidatingBarButtonItem:(UIBarButtonItem *)barButtonItem
{
[self.navigationItem setLeftBarButtonItem:nil animated:YES];
}
#end
Keep in mind that OS 3.2 does not provide proper support for a splitview as a tabbar view.
You can make it "work" but it will have bugs - the biggest is that an orientation change made on another tab's view will often not propagate to the splitview tab view properly, making the view go wacky when you go back to it (left side view takes over the screen, or the barbutton item is missing, etc.).
I've reached the conclusion that I have to create my own splitview for use in a tabBarController because of this issue.
I had heard rumors that Apple was working on a fix but it's been months now and no iPad OS updates have occurred - maybe OS 4 for the iPad will address it.
You can use IB to build tabtab and modify tabs to splitviewcontroller.
-(void) makeSplitViewController {
NSMutableArray *controllers = [NSMutableArray arrayWithArray:tabBarController.viewControllers];
int index = 0;
for (UIViewController *controller in tabBarController.viewControllers) {
if ([controller.tabBarItem.title isEqualToString:#"Stock"]) {
stockDetailController = [[StockDetailController alloc] initWithNibName:#"StockDetailController" bundle:nil];
stockMasterController = [[StockMasterController alloc] initWithStyle:UITableViewStylePlain];
stockMasterController.navigationItem.title = date;
stockMasterController.stockDetailController = stockDetailController;
UINavigationController *nav = [[[UINavigationController alloc] initWithRootViewController:stockMasterController] autorelease];
splitViewController = [[UISplitViewController alloc] init];
splitViewController.tabBarItem = controller.tabBarItem;
splitViewController.viewControllers = [NSArray arrayWithObjects:nav, stockDetailController, nil];
splitViewController.delegate = stockDetailController;
[controllers replaceObjectAtIndex:index withObject:splitViewController];
}
index++;
}
tabBarController.viewControllers = controllers;
}
We succeeded in having a UISplitViewController inside a UITabViewController on iPad with iOS5+.
to make a long story short: it works:
out of the box if you accept a split also in portrait;
with a bit of
work, if you want to have the master view hidden in portrait, and
have it appear only upon tapping a button.
The trick in the second case is to use the IntelligentSplitViewController (see a few posts up, thanx Greg Combs) or similarly extend a UISplitVC, and be careful that the delegate of the subclass of the splitview controller is always a live object.
We have detailed the process on:
https://devforums.apple.com/message/763572#763572