Link to home
Start Free TrialLog in
Avatar of BTMExpert
BTMExpert

asked on

Disable Tab Bar Item

Is there a way to press a button and make one of the tab bar buttons disable or change the view of that tab bar item?
Avatar of tisaksen
tisaksen

You will have to swap it out with a new UITabBarItem.
Just create a new vUITabBarItem object and replace the object you don't want to hang around in the tabbar.
Set the new item array using the UITabBar.items property.

There is no way to disable an item. You can create another view and put that on top of the view you want disabled though. Make sure it does not propagate it's touch events to the view below it. (Not sure if it will by default anyway)
Avatar of BTMExpert

ASKER

Thank you for the answer.  Can you show me how to do that.  I'm new to xcode.
Which one, the replacing of an item or the creation of a new view which will be placed on top of the item you want to disable?
replacing the view will be great.  So when the user clicks the tab bat item it goes to another view right?
This is the code to replace an item:

// create a new UITabBarItem, you decide what value you want to use for tagForNewItem
UITabBarItem *newItem = [[UITabBarItem alloc] initWithTitle:@"Title" image:someImageObject tag:tagForNewItem];
// create a mutable array with the tab bar items
NSMutableArray *barItems = [NSMutableArray arrayWithArray:self.tabBar.items];
// replace item, you must figure out the index of the object,
// typically you would use item.tag when you replace the item when it is clicked but
// otherwise you'll have to find a way to identify it's position in the array to be able to replace it.
[barItems replaceObjectAtIndex:item.tag withObject:newItem];
// set the new item list
self.tabBar.items = barItems;
// don't leak
[newItem release];

Then in -(void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item
you need to check the tag of the newly created item to decide what to do when the item is clicked.

Example:

-(void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item
{
      switch(item.tag)
      {
            case tagForNewItem:
                  // perform your view change code here
            break;
            .......
      }
}
I'm thinking maybe I didn't understand your question.
Is this what you wanted?
i think you got it just one more thing to understand it better.  So the first part grabs the array of items in the tab bar and puts them in an array.  Then from there i replace the first item in the array, since that's the one i'm changing.  How does it know which ViewController and which nib file i want for the new tab bat item?

let me explain
i want the user to be able to click the first tab bar item, then click a button inside that view that sends them to another view that's on the tab bar.  when the user tries to click the first tab bar item again, it should change the view to a different first view.

i think you got it so i'm guessing the method that you sent me changes the view to what i want inside the case switch function
Is there a difference between using UITabBar vs. UITabBarController.  I'm using TabBarController since that's what comes with the template.

still a beginner. sorry.
ASKER CERTIFIED SOLUTION
Avatar of tisaksen
tisaksen

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
NSMutableArray *barItems = [NSMutableArray arrayWithArray:self.tabBar.items];
do i have to declare tabBar as something like UITabBarItem.  it keeps throwing an error
is that -(void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item
in the AppDelegate.m or on the view?
You have to assign a delegate for your UITabBar, typically this delegate is the view controller that created it.

UITabBar *tabBar = ....;
tabBar.delegate = self;

Make sure you implement the protocol in your .h file:

@interface ViewControllerName <UITabBarDelegate>

Then put the didSelectItem: method in the .m file
By doing it that way will i have to declare the UITabBar in every ViewController?
In every view controller you need to use it yes. But you can of course use the AppDelegate for the delegate and to store the UITabBar reference too.
For whatever reason i can't get it to work.  Should i send you my code so you can see or find what i'm missing?
Send me your project and I will have a look.
AppDelegate.h
#import <UIKit/UIKit.h>

@interface TabTestAppDelegate : NSObject <UIApplicationDelegate, UITabBarControllerDelegate> {
    UIWindow *window;
    UITabBarController *tabBarController;
}

@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet UITabBarController *tabBarController;

@end

AppDelegate.m
#import "TabTestAppDelegate.h"


@implementation TabTestAppDelegate

@synthesize window;
@synthesize tabBarController;


#pragma mark -
#pragma mark Application lifecycle

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    
   
    // Override point for customization after application launch.

    // Add the tab bar controller's view to the window and display.
    [window addSubview:tabBarController.view];
    [window makeKeyAndVisible];

    return YES;
}


- (void)applicationWillResignActive:(UIApplication *)application {
    /*
     Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
     Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
     */
}


- (void)applicationDidEnterBackground:(UIApplication *)application {
    /*
     Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
     If your application supports background execution, called instead of applicationWillTerminate: when the user quits.
     */
}


- (void)applicationWillEnterForeground:(UIApplication *)application {
    /*
     Called as part of  transition from the background to the inactive state: here you can undo many of the changes made on entering the background.
     */
}


- (void)applicationDidBecomeActive:(UIApplication *)application {
    /*
     Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
     */
}


- (void)applicationWillTerminate:(UIApplication *)application {
    /*
     Called when the application is about to terminate.
     See also applicationDidEnterBackground:.
     */
}


#pragma mark -
#pragma mark UITabBarControllerDelegate methods

/*
// Optional UITabBarControllerDelegate method.
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController {
}
*/

/*
// Optional UITabBarControllerDelegate method.
- (void)tabBarController:(UITabBarController *)tabBarController didEndCustomizingViewControllers:(NSArray *)viewControllers changed:(BOOL)changed {
}
*/


#pragma mark -
#pragma mark Memory management

- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
    /*
     Free up as much memory as possible by purging cached data objects that can be recreated (or reloaded from disk) later.
     */
}


- (void)dealloc {
    [tabBarController release];
    [window release];
    [super dealloc];
}

@end

FirstViewController.h
#import <UIKit/UIKit.h>


@interface FirstViewController : UIViewController {
      UIButton *dis;
}

@property (nonatomic, retain) IBOutlet UIButton *dis;

-(IBAction) display:(id) sender;

@end

FirstViewController.m
@implementation FirstViewController
@synthesize dis;

-(IBAction) display:(id) sender{
      [[[[[self tabBarController] viewControllers] objectAtIndex:0] tabBarItem] setEnabled:false];
}

SecondViewController.h
@interface SecondViewController : UIViewController {
      UIButton *dis2;
}

@property (nonatomic, retain) IBOutlet UIButton *dis2;

-(IBAction) diss:(id) sender;

@end

SecondViewController.m
@implementation SecondViewController
@synthesize dis2;

-(IBAction) diss:(id) sender{
      [[[[[self tabBarController] viewControllers] objectAtIndex:0] tabBarItem] setEnabled:true];
}







This is the effect that i want kind of but instead of disabling the button i want it to show another view like we talked about.  FirstAViewController
I don't think you can use UITabBarController for this. Looks like it limits your options.. You need to set the delegate of the actual tabbar to be your AppDelegate object. Otherwise you wont be able to handle didSelect:item
AppDelegate.h
#import <UIKit/UIKit.h>

@interface DisDatTestAppDelegate : NSObject <UIApplicationDelegate, UITabBarControllerDelegate> {
    UIWindow *window;
    UITabBarController *tabBarController;
      UITabBar *tabBar;
}

@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet UITabBarController *tabBarController;
@property (nonatomic, retain) IBOutlet UITabBar *tabBar;

@end

AppDelegate.m
#import "DisDatTestAppDelegate.h"


@implementation DisDatTestAppDelegate

@synthesize window;
@synthesize tabBarController;
@synthesize tabBar;


-(void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item
{
      switch(item.tag)
      {
            case 0:
                  // first item
                  // display the view you want the first time
                  //YourViewController *ctrl = .........;
                  // addSubview or whatever you use to display it (might be a navigationController, I dont know)
            break;
            case 1:
                  // second item
            break;
            case 2:
                  // third item
                  // let's say this is the one which presents your view with a button,
                  // that when clicked, should replace the first item on the tabbar
                  // in the replace tabbar item code, set the tag of the new item to some far out value, like 9999 or whatever
                  // ie: UITabBarItem *newItem = [[UITabBarItem alloc] initWithTitle:@"Title" image:someImageObject tag:9999];
            break;
            case 9999:
                  // display the different view when the user clicks the first item on the tab bar
                  //DifferentViewForFirstTabBarItem *differentView = .....
                  // addSubview or whatever you use to display it (might be a navigationController, I dont know)
                  // if you need to replace the first tab bar item again remember to set it's tag to 0 this time.
            break;
           
            // .........
      }
}
#pragma mark -
#pragma mark Application lifecycle

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    
   
    // Override point for customization after application launch.

    // Add the tab bar controller's view to the window and display.
    [window addSubview:tabBarController.view];
    [window makeKeyAndVisible];

    return YES;
}


- (void)applicationWillResignActive:(UIApplication *)application {
    /*
     Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
     Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
     */
}


- (void)applicationDidEnterBackground:(UIApplication *)application {
    /*
     Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
     If your application supports background execution, called instead of applicationWillTerminate: when the user quits.
     */
}


- (void)applicationWillEnterForeground:(UIApplication *)application {
    /*
     Called as part of  transition from the background to the inactive state: here you can undo many of the changes made on entering the background.
     */
}


- (void)applicationDidBecomeActive:(UIApplication *)application {
    /*
     Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
     */
}


- (void)applicationWillTerminate:(UIApplication *)application {
    /*
     Called when the application is about to terminate.
     See also applicationDidEnterBackground:.
     */
}


#pragma mark -
#pragma mark UITabBarControllerDelegate methods

/*
// Optional UITabBarControllerDelegate method.
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController {
}
*/

/*
// Optional UITabBarControllerDelegate method.
- (void)tabBarController:(UITabBarController *)tabBarController didEndCustomizingViewControllers:(NSArray *)viewControllers changed:(BOOL)changed {
}
*/


#pragma mark -
#pragma mark Memory management

- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
    /*
     Free up as much memory as possible by purging cached data objects that can be recreated (or reloaded from disk) later.
     */
}


- (void)dealloc {
    [tabBarController release];
    [window release];
    [super dealloc];
}

@end

FirstViewController.h
#import <UIKit/UIKit.h>


@interface FirstViewController : UIViewController {
      IBOutlet UIButton *dis;
}

@property (nonatomic, retain) UIButton *dis;

-(IBAction) disable:(id)sender;

@end

FirstViewController.m
#import "FirstViewController.h"
#import "DisDatTestAppDelegate.h"

@implementation FirstViewController

@synthesize dis;

-(IBAction) disable:(id)sender {
      UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Test" message:@"Test" delegate:self cancelButtonTitle:@"Ok" otherButtonTitles:nil];
      
      [alert show];
      [alert release];
      
      /*UIImage* anImage = [UIImage imageNamed:@""];
      UITabBarItem *newItem = [[UITabBarItem alloc] initWithTitle:@"Title" image:anImage tag:0];
      
      NSMutableArray* newArray = [NSMutableArray arrayWithArray:self.tabBarController.viewControllers];
      
      [newArray replaceObjectAtIndex:0 withObject:newItem];
      
      [self.tabBarController setViewControllers:newArray animated:YES];*/
      
      UIImage* anImage = [UIImage imageNamed:@""];
      UITabBarItem *newItem = [[UITabBarItem alloc] initWithTitle:@"Title" image:anImage tag:0];
      // create a mutable array with the tab bar items
      NSMutableArray *barItems = [NSMutableArray arrayWithArray:self.tabBar.items];
      // replace item, you must figure out the index of the object,
      // typically you would use item.tag when you replace the item when it is clicked but
      // otherwise you'll have to find a way to identify it's position in the array to be able to replace it.
      [barItems replaceObjectAtIndex:0 withObject:newItem];
      // set the new item list
      //[self.tabBarController setViewControllers:barItems animated:YES];
      // don't leak
      [newItem release];
      [anImage release];
      
}




/*
// 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
    }
    return self;
}
*/

/*
// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView {
}
*/

/*
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
    [super viewDidLoad];
}
*/

/*
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    // Return YES for supported orientations
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
*/

- (void)didReceiveMemoryWarning {
      // Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];
      
      // Release any cached data, images, etc that aren't in use.
}

- (void)viewDidUnload {
      // Release any retained subviews of the main view.
      // e.g. self.myOutlet = nil;
}


- (void)dealloc {
    [super dealloc];
}

@end