I am wondering if there is a way to add an additional UITabBarItem to my exisiting UITabBarController. It doesn't need to be in runtime.
All I want to do is when hitting this button I want to presentModalViewController: over my actually visible ViewController, which should either be the TabBarController or its controllers.
Hopefully this is clear enough, if not, feel free to ask.
As a result of my research you cannot add a UITabBarItem to a UITabBar that is managed by a UITabBarController.
Since you maybe have added your UITabBarItem by adding a list of view controller, this is also the way of your choice to add further custom UITabBarItems, as i will show now:
Pre-Conditions:
As i mentioned before, you maybe have added your UITabBarItems by adding a list of view controller:
tabbarController = [[UITabBarController alloc] init]; // tabbarController has to be defined in your header file
FirstViewController *vc1 = [[FirstViewController alloc] initWithNibName:#"FirstViewController" bundle:[NSBundle mainBundle]];
vc1.tabBarItem.title = #"First View Controller"; // Let the controller manage the UITabBarItem
SecondViewController *vc2 = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:[NSBundle mainBundle]];
vc2.tabBarItem.title = #"Second View Controller";
[tabbarController setViewControllers:[NSArray arrayWithObjects: vc1, vc2, nil]];
tabbarController.delegate = self; // do not forget to delegate events to our appdelegate
Adding custom UITabBarItems:
Now since you know how to add UITabBarItems through adding view controller, you can also use the same way to add custom UITabBarItems:
UIViewController *tmpController = [[UIViewController alloc] init];
tmpController.tabBarItem.title = #"Custom TabBar Item";
// You could also add your custom image:
// tmpController.tabBarItem.image = [UIImage alloc];
// Define a custom tag (integers or enums only), so you can identify when it gets tapped:
tmpController.tabBarItem.tag = 1;
Modify the line above:
[tabbarController setViewControllers:[NSArray arrayWithObjects: vc1, vc2, tmpController, nil]];
[tmpController release]; // do not forget to release the tmpController after adding to the list
All fine, now you have your custom button in your TabBar.
What about handling events of this custom UITabBarItem?
Its easy, look:
Add the UITabBarControllerDelegate to your AppDelegate class (or the class which is holding the tabbarController).
#interface YourAppDelegate : NSObject <UIApplicationDelegate, UITabBarControllerDelegate> { }
Fit the protocol definition by adding this function:
- (void)tabBarController:(UITabBarController *)theTabBarController didSelectViewController:(UIViewController *)viewController {
NSUInteger indexOfTab = [theTabBarController.viewControllers indexOfObject:viewController];
UITabBarItem *item = [theTabBarController.tabBar.items objectAtIndex:indexOfTab];
NSLog(#"Tab index = %u (%u), itemtag: %d", indexOfTab, item.tag);
switch (item.tag) {
case 1:
// Do your stuff
break;
default:
break;
}
}
Now you have all you need to create and handle custom UITabBarItems.
Hope this helps.
Have fun....
Access the tabBar - property of your UITabBarController (reference), grab the elements array with the items - property (reference), add a new UITabBarItem to this array and use the tabBar's setItems:animated: - method to update your tab bar. Add an action to this tab bar to display the modal view controller.
Related
I created an onscreen tutorial for my iOS app.
To accomplish this I'm using a UIPageViewController which is managing 3 viewControllers.
- (void)setupContentViews{
UIViewController *screenTutorial1 = [[UIViewController alloc] initWithNibName:#"ScreenTutorial_1ViewController" bundle:nil];
UIViewController *screenTutorial2 = [[UIViewController alloc] initWithNibName:#"ScreenTutorial_2ViewController" bundle:nil];
tutorialPages = #[screenTutorial1, screenTutorial2];
}
Everything works great, except that when I got to change the background for screenTutorial1 or screenTutorial2 it never gets called. What's the reason for this? Is there a solution?
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = [UIColor redColor];
NSLog(#"line 30)");
}
After some experimentation it appears that if I add the code in UIPageViewController (see below) it sets the property. But what if I need to add any custom methods to my View Controllers? Do I need to do everything from UIPageViewController?
The problem is that at that point the view is nil so you can't change the backgroundColor.
You should subclass UIViewController and set the backgroundColor in viewDidLoad. And after that you should initialize the view controllers for the tutorialPages ivar like this:
YourUIViewControllerSubclass *screenTutorial1 = [[YourUIViewControllerSubclass alloc] initWithNimbName:#"ScreenTutorial_1ViewController" bunble:nil];
Update
Update your method setupContentViews like this:
- (void)setupContentViews
{
ScreenTutorial_1ViewController *screenTutorial1 = [[ScreenTutorial_1ViewController alloc] initWithNibName:#"ScreenTutorial_1ViewController" bundle:nil];
UIViewController *screenTutorial2 = [[UIViewController alloc] initWithNibName:#"ScreenTutorial_2ViewController" bundle:nil];
tutorialPages = #[screenTutorial1, screenTutorial2];
}
I don't know if what I'm trying to do is possible, but because I haven't the desired results, I guess not.
What I'm trying and need to do is to call a SplitViewController from a previous ViewController, using presentViewController.
I know, SplitViewController have to be the rootViewController, but I need to explore the most possible options to achieve what I need to do.
I have a MainMenu with buttons, and with every button, I need to call a SplitViewController. First, how can do this?
What I'm trying to do is this:
First, in AppDelegate I'm calling the MainMenu, and add as a subview and other things:
-(BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[window addSubview:self.mainMenu.view];
[self.mainMenu presentModalViewController:self.firstMenu animated:NO];
[self.window makeKeyAndVisible];
return YES;
}
Then, in the MainMenu, I'm calling SecondViewController, in modal view, using this code:
SecondViewController *secV = [[SecondViewController alloc]initWithNibName:#"SecondViewController" bundle:nil];
secV.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:secV animated:YES];
In this SecondViewController, I'm creating SplitViewController, with Master & DetailViewController's, using this code:
-(void)viewDidLoad{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
UISplitViewController *splitViewController = [[UISplitViewController alloc]init];
SecondMenuViewController *secMenu = [[SecondMenuViewController alloc]init];
UINavigationController *navLef = [[UINavigationController alloc]init];
[navLef pushViewController:secMenu animated:NO];
SecondMainViewController *secMain = [[SecondMainViewController alloc]init];
UINavigationController *navRig = [[UINavigationController alloc]init];
[navRig pushViewController:secMain animated:NO];
splitViewController.delegate = secMain;
splitViewController.viewControllers = [NSArray arrayWithObjects:navLef, navRig, nil];
MainAppDelegate *mainApp = [[MainAppDelegate alloc]init];
[mainApp changeRootViewController:splitViewController];
navRig = nil;
navLef = nil;
secMain = nil;
secMenu = nil;
splitViewController = nil;
}
As you can see, I'm calling a method in MainAppDelegate, to change view and RootViewController, because SplitViewController have to be RootViewController. This is the method:
-(void)changeRootViewController:(UISplitViewController *)splitViewController{
[self.window addSubview:splitViewController.view];
self.window.rootViewController = splitViewController;
}
I know, this looks like a mess. And when I run, the SplitViewController never shows, so I assume, what I'm trying to do is not possible? Or In what I'm wrong?
If it is everything, what can I do to show a SplitViewController after my MainViewController?
I'm using XCode4.4 and iOS5
Thank you very much
A better way would be to make your UISplitViewController the root view controller in application:didFinishLaunchingWithOptions:. Then present your MainMenu on top of it. You can change the subviews displayed by the split view controller to correspond to what button the user pushes in your MainMenu.
First, didFinishLaunchingWithOptions: is too early to be calling presentModalViewController. You haven't even got an interface yet!
Second, you don't seem to have a root view controller (although perhaps you're getting one from a nib? you should probably stop doing that; use the techniques shown in the current application templates).
Third, note that now that we have custom container views, there is no need for you to use UISplitViewController at all; you can construct your own view / view controller hierarchy, and you might be happier doing so, since UISplitViewController is not a very well-constructed class.
I'm creating an App for Ipad, I created 3 views with a navigation bar but I would to start my application not in first but in second view, what can i do?
You can setup UINavigationController with an initial navigation stack via setViewControllers:animated:.
// in application:didFinishLaunchingWithOptions:
self.navigationController = [[UINavigationController new] autorelease];
UIViewController *first = [[MyFirstViewController new] autorelease];
UIViewController *second = [[MySecondViewController new] autorelease];
NSArray *controllers = [NSArray arrayWithObjects:first, second, nil];
[navigationController setViewControllers:controllers animated:NO];
...
[window addSubview:navigationController.view];
Initialise your navigation controller on startup programmatically with 2 controllers already in stack:
FirstViewController *first = ...//create controller
SecondViewController *second = ...//create controller
[navigationController setViewControllers:[NSArray arrayWithObjects:first, second, nil]
animated:NO];
Or alternatively you can make your 1st controller push the second one on startup - see Apple's DrillDownSave sample for that technique.
Follow somesteps as:
1.open the MainWindow.xib in resource folder or bundle.
2.click on Tool and open Inspector >> choose attribute >> NIB Name-set here your view name from drop down list >> identity in inspector(from upper tabs) >> choose class -set here your view name again from drop down list.
3.Open appdelegate.m file
change here the view controller as : fileviewcontrollername *viewController;
set it's property.
4.in didFinishLaunching in appdelegate.m add
UINavigationController *navController=[[UINavigationController alloc]initWithRootViewController:viewController];[window insertSubview:navController.view];[self.window makeKeyAndVisible];return YES;
5.In appdelegate.h file add
#class viewControllername;
In my AppDelegate, I create a UITabBarController and UINavigationController dynamically. I then add 3 views to it.
// Prepare the tab bar controller
tabBarController = [[UITabBarController alloc] init];
// Switch controller
UserSettingsController *settingsController = [[UserSettingsController alloc] init];
// Switches controller
SwitchesController *switchesController = [[SwitchesController alloc] init];
// Help controller
HelpController *helpController = [[HelpController alloc] init];
NSArray *controllers = [NSArray arrayWithObjects: switchesController, settingsController, helpController, nil];
tabBarController.viewControllers = controllers;
if (self.navigationController == nil) {
self.navigationController = [[UINavigationController alloc] initWithRootViewController:tabBarController];
}
[window addSubview:navigationController.view];
When I initially did this, I noticed that I now have a header/title bar at the top of my page. It's blank and really just takes up space. I'd like to utilize it though and add a "refresh" button to one of my views.
In the view I'm interested in, I attempted the following:
-(void)viewDidLoad {
[super viewDidLoad];
UIBarButtonItem *refresh = [[UIBarButtonItem alloc] initWithTitle:#"Refresh" style:UIBarButtonItemStylePlain target:self action:#selector(refreshSwitches:)];
self.navigationItem.rightBarButtonItem = refresh;
[refresh release];
}
-(void)refresh{
...
}
No button showed up, so I'm either way off or I'm missing something.
Any suggestions?
Thanks
I believe the problem is that your view controllers that you've added to the tabbar controller are not encapsulated by navigation controllers. Although your UITabBarController has a navigation controller, this does not implicitly give all of its tabs navigation controllers (and without a nav controller, a view controller's navigationItem won't do anything.) To remedy this problem I'd suggest encapsulating your view controllers with navigation controller upon initialization:
ex:
UserSettingsController *settingsController = [[UserSettingsController alloc] init];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:settingsController];
[settingsController release];
// etc...
NSArray *controllers = [NSArray arrayWithObjects:navController, ..., ..., nil];
tabBarController.viewControllers = controllers;
// Release your nav controllers, other cleanup
EDIT
Okay, I think I have a better idea of your setup now. I was able to get the following to work:
self.tabBarController.navigationItem.rightBarButtonItem = myButton;
An important caveat of this is that the button will persist on all of your tabbarcontroller's views unless you explicitly remove it. This may prove annoying/inelegant to maintain, but I am not sure of another solution if the view you want to have the button is not directly associated to a nav controller itself.
I'm triying to combine a TabBar + Navigation app.
I have 5 tab bars, 4 are listing of stuff and drill down to details views.
I try to follow this tutorial:
http://www.iphonedevforums.com/forum/iphone-sdk-development/124-view-controller-problem.html
But always get a blank view.
This is what I do, with a clean project:
I start with a TabBar template app.
I put 5 tab bar buttons.
I create a controller like:
#interface FirstViewController : UINavigationController {
}
I put the main window.xib on tree mode & change the selected first view to FirstViewController
I select the TabBar Controller in Interface builder, go to TabBar Attributes & change the class to navigation controler.
Select the fist view & put the nib name "SecondView"
In response, I get a blank screen.
I must add that I wanna navigate from the details views, no from the main windows.
i.e in the main window tab bar 1 is the list of people. I select a person then wanna navigate to the detail window.
First, you never want to subclass UINavigationController or UITabBarController.
Second, I did not quite get what you did, but a correct sequence to create a navigation controller inside a tab bar controller is something like this:
// in MyAppDelegate.h
UINavigationController *nc1, *nc2;
FirstTabRootViewController *vc1;
SecondTabRootViewController *vc2;
UITabBarController *tbc;
// in MyAppDelegate.m
nc1 = [[UINavigationController alloc] init];
vc1 = [[FirstTabRootViewController alloc] initWithNibName:nil bundle:nil];
vc1.tabBarItem.title = #"Tab 1";
vc1.tabBarItem.image = [UIImage imageNamed:#"tab1.png"];
vc1.navigationItem.title = "Tab 1 Data";
nc1.viewControllers = [NSArray arrayWithObjects:vc1, nil];
nc2 = [[UINavigationController alloc] init];
vc2 = [[SecondTabRootViewController alloc] initWithNibName:nil bundle:nil];
vc2.tabBarItem.title = #"Tab 2";
vc2.tabBarItem.image = [UIImage imageNamed:#"tab2.png"];
vc2.navigationItem.title = "Tab 2 Data";
nc2.viewControllers = [NSArray arrayWithObjects:vc2, nil];
tbc = [[UITabBarController alloc] init];
tbc.viewControllers = [NSArray arrayWithObjects:nc1, nc2, nil];
Note that it's your view controller that controls the text/icon in the tab bar and in the navigation bar. Create a UINavigationController instance for each of your tabs; UINavigationController contains a stack of view controllers (see viewControllers property) which should contain at least one item — your root controller for that tab. Also create an UITabBarController to manage the tabs.
Of course, you can (and probably should) use interface builder instead of code to instantiate the mentioned classes and set the properties. But it's important that you understand what happens behind the scenes; interface builder is nothing more than a convenient way to instantiate and set up objects.
Hope this is helpful; please refine your question if it's not.
Still getting the blank screen On Starting the application after implementing the above code. Where i 'm writing it wrong.
nc1 = [[UINavigationController alloc] init];
nc2 = [[UINavigationController alloc] init];
vc1 = [[FirstRootViewController alloc]initWithNibName:#"FirstRootViewController" bundle:nil];
vc1.tabBarItem.title = #"Item 1";
vc1.tabBarItem.image= [UIImage imageNamed:#"home.png"];
vc1.navigationItem.title = #"Tab1 Data";
nc1.viewControllers = [NSArray arrayWithObjects:vc1,nil];
vc2 = [[SecondRootViewController alloc]initWithNibName:#"SecondRootViewController" bundle:nil];
vc2.tabBarItem.title = #"Item 2";
vc2.tabBarItem.image= [UIImage imageNamed:#"home.png"];
vc2.navigationItem.title = #"Tab2 Data";
nc2.viewControllers = [NSArray arrayWithObjects:vc2,nil];
tbc = [[UITabBarController alloc]init];
tbc.viewControllers = [NSArray arrayWithObjects:nc1,nc2,nil];
[window addSubview:tbc.view];
[window makeKeyAndVisible];
Here is an tutorial that I was able to get working.
I also read the official SDK documentation on the topic: Combining Tab Bar and Navigation Controllers. Since I'm still learning, the tutorial helped me more than the docs.
NOTE: in the tutorial, i don't think you need to subclass UINavigationController, and I'm experimenting with this idea now.
I tried to create an iphone application with UITabBarController and some UINavigationController inside it and faced the same problems as "mamcx". With your example-code i get it to run :) Thanks a lot.
Here is how it works for me.
// YOURS
fourthNavigation = [[UINavigationController alloc ] init ];
fourthViewController = [[[FourthTabRootController alloc] initWithNibName:#"FourthView" bundle:nil] autorelease];
fourthNavigation.tabBarItem.title = #"YOURS";
fourthNavigation.viewControllers = [NSArray arrayWithObjects:fourthViewController, nil];
// Add self-defined UIViewControllers to the tab bar
tabBarController.viewControllers = [NSArray arrayWithObjects:firstNavigation,secondNavigation, thirdNavigation, fourthNavigation, nil];
// Add the tab bar controller's current view as a subview of the window
[window addSubview:tabBarController.view];
The other UINavigationControllers "firstNavigation, ... " are created the same way.
I load the view elements from nib-files that are connected to my subclassed UIViewController classes. You dont need to add a NavigationBar in the IB to your view, cause the UINavigationController has allready one. So you only need to set the title in "initWithNibName"
// The designated initializer. Override to perform setup that is required before the view is loaded.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
// Custom initialization
self.title = #"YOURS";
}
return self;
}
I hope that helps.
Check out "Adding a Navigation Controller to a Tab Bar Interface" under View Controller Catalog for iOS which take you step by step into how exactly this can be achieved