In my header file I have this:
#interface TabBarController : UIViewController <UIApplicationDelegate, UITabBarDelegate, UITabBarControllerDelegate>{
IBOutlet UITabBarController *tabBarController;
}
-(void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item;
#property (nonatomic, retain) IBOutlet UITabBarController *tabBarController;
#end
In my main file I have this:
#synthesize tabBarController;
-(void)viewDidLoad{
[super viewDidLoad];
self.tabBarController.delegate = self;
self.view = tabBarController.view;
}
-(void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item{
NSLog(#"rawr");
}
- (void)viewDidUnload {
[super viewDidUnload];
}
- (void)dealloc {
[tabBarController release];
[super dealloc];
}
#end
I have already connected my tabbarcontroller as a delegate to my file's owner in interface builder, but it still never calls the didSelectItem method.
Is there anything that I'm missing here?
I have already added tabBarController.delegate = self; and it still does not work.
-(void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item;
This method is a delegate method for UITabBar, not UITabBarController, so
self.tabBarController.delegate = self;
will not work.
Tab bar controller has its own UITabBar, but changing the delegate of a tab bar managed by a tab bar controller is not allowed, so just try UITabBarControllerDelegate method like this:
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController
You need to add this:
tabbarcontroller.delegate = self;
Use UITabBarControllerDelegate instead of UITabBarDelegate and -tabBarController:didSelectViewController{} instead of tabBar:didSelectItem{}
Interface
#interface TabBarController : UIViewController <UIApplicationDelegate, UITabBarControllerDelegate, UITabBarControllerDelegate>{
IBOutlet UITabBarController *tabBarController;
}
#property (nonatomic, retain) IBOutlet UITabBarController *tabBarController;
#end
main file
#implementation TabBarController
#synthesize tabBarController;
/*other stuff*/
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController{
NSLog(#"rawr");
}
/*other stuff*/
#end
Just set the delegate for the tab bar. You can do it by setting self.tabBarController.delegate = self; or using Interface builder do to the tabbarcontroller object (not bar) see the connection inspector and drag the connection on the file's owner.
You have synthesized the tab bar, so you now need to write: self.tabBarController.delegate = self;
There are many reasons, as indicated above, why it might not be working. Here is a more subtle reason. If you are creating your UI programatically (no storyboard or Xib) you need to set the screen of your UIWindow.
self.window = [[UIWindow alloc] init];
self.window.screen = [UIScreen mainScreen]; // <- The UITabViewController will not
// accept taps without this.
If you are using a Xib, I believe this is equivalent to having "Full Screen at Launch" selected. That has to be checked or I have noticed my Tabs don't work.
I had a non-working tab controller and this is what I had to do to get it working. None of the other answers on this page helped me. I suppose using a xib/storyboard is pretty rare these days (I think this was from iOS 5 days) but leaving here for the person that does and stumbles into this situation.
Related
I have created a custom UITabBarController by using Martin's tutorial.
My subclass FSTabBarController switches between view controllers, and acts normal as far as I can see.
The issue is, when I change my tabBarContoller to my subclass, It won't respond to my delegate;
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController
If I change it back to UITabBarController -when I use the default UITabBarController- the delegates works as it should.
The custom subclass uses the below function to represent tab selection:
- (void)_buttonClicked:(id)sender
{
self.selectedIndex = [sender tag];
[self _updateTabImage];
}
Edit:
AppDelegate.h
...
#interface AppDelegate : UIResponder <UIApplicationDelegate,UITabBarControllerDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (strong, nonatomic) FSTabBarController *tabBarController;
AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
...
self.tabBarController = [[FSTabBarController alloc] init];
self.tabBarController.viewControllers = [NSArray arrayWithObjects:peopleViewController,viewController,profileViewController, nil];
self.tabBarController.delegate = self;
...
}
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController
{
// not called when FSTabBarController, called when UITabBarController !!
}
OK, downloaded the sample from his site and tested.
Yes you need to manually call the deleage from the subclass:
this is how you should change the buttonClicked function:
- (void)_buttonClicked:(id)sender
{
self.selectedIndex = [sender tag];
if (self.delegate) {
[self.delegate tabBarController:self didSelectViewController:self.selectedViewController];
}
[self _updateTabImage];
}
I could use some help with custom delegates. I'm trying to make a protocol that sends a message to its delegate to dismiss the popover view. Here is what I'm trying.
In the popoverViewController.h
#import <UIKit/UIKit.h>
#protocol MyPopoverDelegate <NSObject>
-(void) didSelectLanguage;
#end
#interface Popover : UITableViewController{
id <MyPopoverDelegate> delegate;
NSMutableArray *languageData;
}
#property (nonatomic, assign) id <MyPopoverDelegate> delegate;
#end
.m
#synthesize delegate;
...
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"You selected %#", [languageData objectAtIndex:[indexPath row]]);
[self.delegate didSelectLanguage];
}
...
And in the ViewController that presents the popover
#import <UIKit/UIKit.h>
#import "popoverViewController.h"
#interface ChoicesChoices : UIViewController <UIPopoverControllerDelegate, MyPopoverDelegate>{
UIPopoverController *popover;
}
- (IBAction)facebook:(id)sender;
- (IBAction)twitter:(id)sender;
- (IBAction)sms:(id)sender;
- (IBAction)copy:(id)sender;
- (IBAction)email:(id)sender;
- (IBAction)home:(id)sender;
- (IBAction)mute:(id)sender;
- (IBAction)note:(id)sender;
#property (nonatomic, retain) UIPopoverController* popover;
#end
and .m
#synthesize popover;
...
- (void)didSelectLanguage{
[popover dismissPopoverAnimated:YES];
NSLog(#"didSelectLanguage fired");
}
When I select a row in the table of the popover, didSelectLanguage does not get called. Any ideas on what I might be doing wrong? Thanks for your help.
Make sure you are setting your delegate to the be the view controller that is presenting your popover. Something like this in ChoicesChoices.m:
- (void)presentPopover
{
// assuming ARC for all allocations
Popover *myController = [Popover new];
myController.delegate = self;
self.popover = [[UIPopoverController alloc] initWithContentViewController:myController];
[self.popover presentPopover...]; // two flavors here, FromRect: and FromBarButtonItem:, that's left up to you to choose which one is correct.
}
Make sure you set the delegate in the presenting view controller when you create the instance of your custom class.
popover.delegate = self
Also, it looks like your property is a standard popover controller instead of an instance of your custom view controller.
I'm creating an iPhone app with UITabBarController.
What I want to achieve is that when I tap some items on tabbar I don't want them to activate new view, instead of it I want them to run some functionality in the current view.
For example I have a view with map active and when I click some item on tabbar I want it to locate the current position on the map.
I don't know if using UITabBarController is the best solution for this. I'll also want 1 item to swap between 2 views (map / list).
Would it be better to use some kind of ToolBar on bottom or anything completely different?
I don't think there is any code needed, but I've got a UITabBarViewController app created and I created a UITabBarControllerDelegate like this:
#interface MainTabBarControllerDelegate : NSObject <UIApplicationDelegate, UITabBarControllerDelegate> {
UIWindow *window;
UITabBarController *tabBarController;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet UITabBarController *tabBarController;
#end
and
#implementation MainTabBarControllerDelegate
#synthesize tabBarController, window;
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
tabBarController.delegate = self;
[window addSubview:tabBarController.view];
}
- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController{
return YES;
}
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController{
}
#end
But I don't know how to achieve the functionality.
Thanks.
You're right, you don't need a UITabBarController for this. A UIToolbar or your own custom UIView would be enough. But if you want to use UITabBarController, you'll have to override its usual functioning:
- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController{
return NO; //do not select any view controller here
}
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController{
// find which tab was tapped here and handle the map's current position
// location operation accordingly
}
You can also refer to this link for more tips...
Basically, I have two view controllers inside the MainWindow.xib that can be viewed by clicking the Bar Button in my Navigation Controller. I wanted those two view controllers to be separated from the MainWindow.xib with their own header, implementation and xib files and still make Navigation Controller inside of MainWindow.xib work in them.
To better understand it, please see the codes below:
Thanks a lot!
TestAppDelegate.h
#import <UIKit/UIKit.h>
#interface TestAppDelegate : NSObject <UIApplicationDelegate>
{
//Navigation Controller
IBOutlet UINavigationController *navigationController;
//View Controllers
UIViewController *viewController;
UIViewController *viewController2;
UIViewController *viewController3;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
//Navigation Controller
#property (nonatomic, retain) IBOutlet UINavigationController *navigationController;
//View Controllers
#property (nonatomic, retain) IBOutlet UIViewController *viewController;
#property (nonatomic, retain) IBOutlet UIViewController *viewController2;
#property (nonatomic, retain) IBOutlet UIViewController *viewController3;
- (IBAction)next;
- (IBAction)next2;
#end
TestAppDelegate.m
#import "TestAppDelegate.h"
#implementation TestAppDelegate
#synthesize window = _window;
//Navigation Controller
#synthesize navigationController;
//View Controllers
#synthesize viewController;
#synthesize viewController2;
#synthesize viewController3;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
//Navigation Controller
[self.window addSubview:[navigationController view]];
[self.window makeKeyAndVisible];
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application
{
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
}
- (void)applicationWillTerminate:(UIApplication *)application
{
}
- (void)dealloc
{
[viewController release];
[viewController2 release];
[viewController3 release];
[navigationController release];
[_window release];
[super dealloc];
}
- (IBAction)next {
[navigationController pushViewController:viewController2 animated:YES];
}
- (IBAction)next2 {
[navigationController pushViewController:viewController3 animated:YES];
}
#end
Inside MainWindow.xib:
http://i52.tinypic.com/10xa45f.png
I normally don't touch MainWindow.xib. I suggest the following:
Create a MainController which will be your MainView that subclass UIViewController by going to File > New > New File. That will create a .h/.m and nib file for each ViewController. There add whatever UI you want for your app. For Example, add two buttons and wire those buttons to IBActions in your MainController. This should be declared and implemented in your MainController.{h/m}, respectively.
After that create another two ViewControllers, the same way.
The body of those IBActions should create an instance of the your ViewControllers and then push them.
It would look something like this:
YourViewController *yvc = [[YourViewController alloc] init];
[self.navigationController pushViewController:yvc animated:YES];
[yvc release];
Finally, you have to push the MainController in your AppDelegate and add your NavigationController to the view.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
MainViewController *mvc = [[MainViewController alloc] init];
UINavigationController *unvc = [[UINavigationController alloc] init];
[unvc pushViewController:mvc animated:NO];
[mvc release];
[self.window addSubview:unvc.view];
[self.window makeKeyAndVisible];
return YES;
}
Set the "class" property in Interface Builder (third tab in the inspector, "Custom Class") to the name of the custom class you're planning to use, and then put the name of the .xib file you want to load from in the "NIB Name" (fourth tab).
The code you're using to push the viewController is alright. Make sure to never accidentaly dealloc any of the two UIViewController.
Speaking of which, keep in mind that this approach is keeping the ViewControllers always in memory, even when not in use. Another approach is to completely remove the IBOutlets for the two ViewControllers, and do something like:
- (IBAction)next
{
MyCustomViewController *customViewController = [[MyCustomViewController alloc] initWithNibName:<#NibName or nil#> bundle:[NSBundle mainBundle]];
[navigationController pushViewController:customViewController animated:YES];
[customViewController release];
}
This creates the object when needed (If I remember right, the UI elements from the xib are cached somewhere, so that may be irrelevant[citation needed]). Just something to keep in mind, depending on the frequency of use of your two ViewControllers.
Here is my code stub for my app-delegate.m -- it never gets called.
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController {
NSLog(#"%s", __FUNCTION__);
}
It is defined in this app-delegate.h
#interface OrioleAppDelegate : NSObject <UIApplicationDelegate, UITabBarControllerDelegate> {
UIWindow *window;
UITabBarController *tabBarController;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet UITabBarController *tabBarController;
#end
Did you make a connection between your UITabBarController and your application delegate?
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
...
tabBarController.delegate = self;
...
}
If your ViewController is a UITabBarController, you need to set self as it's delegate because you can't change the delegate of the UITabBar directly.
For example, in the ViewDidLoad of your UITabBarController :
- (void)viewDidLoad
{
[super viewDidLoad];
self.delegate = self;
}
I added the following tabBarController.delegate = self; and all is well. I hope this is helpful to others.
- (void)applicationDidFinishLaunching:(UIApplication *)application {
// Add the tab bar controller's current view as a subview of the window
tabBarController.delegate = self;
[window addSubview:tabBarController.view];
}