Speckpgh
Speckpgh

Reputation: 3372

iOS didSelectTabBarItem knowing what item was selected prior

I have an IOS app with a UITabBar and have its delegate set to my class.. the didSelectTabBarItem properly fires and all is right with the world. However I do have some conditional code that has to occur when the UITabBarItem selected is after one particular UITabBarItem IE.. if the user clicks on tab bar item 3, and they were currently on tab bar item 2 I have to do a little extra code, that I would not have to do if the user selected tab bar item 3 and was previously on tab bar item 1.

So, is there anyway programmatically (other than keeping direct track via my program via a state variable, to know what was the previously selected item was on a tab bar when a new tab bar item is selected?

Upvotes: 3

Views: 4209

Answers (5)

Stunner
Stunner

Reputation: 12214

I found that this works with ReactiveCocoa:

#import <ReactiveCocoa/ReactiveCocoa.h>
// ...
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
@weakify(self);
[RACObserve(appDelegate, tabBarController.tabBar.selectedItem) subscribeNext:^(UITabBarItem *selectedTab) {
    @strongify(self);
    NSUInteger selectedIndex = [appDelegate.tabBarController.tabBar.items indexOfObject:selectedTab];
    NSLog(@"selected index: %lu", (unsigned long)selectedIndex);
}];

Upvotes: 0

NJones
NJones

Reputation: 27147

Yes it is possible, through key-value-observing (KVO).

note This answer is in regard to a UITabBar not a UITabBarController. Tab bar controller delegates have methods you are looking for (as mentioned by rdelmar).

To start, observe your tab bar like so:

- (void)viewDidLoad{
    [super viewDidLoad];
    [self.tabBar addObserver:self forKeyPath:@"selectedItem" options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew context:nil];
}

I think you can already see where I'm going based on my using both options old & new. Then simply observe the change instead of using the delegate method, like so:

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
    if ([keyPath isEqualToString:@"selectedItem"] && [object isKindOfClass:[UITabBar class]]){
        UITabBar *bar = (UITabBar *)object; // The object will be the bar we're observing.
        // The change dictionary will contain the previous tabBarItem for the "old" key.
        UITabBarItem *wasItem = [change objectForKey:NSKeyValueChangeOldKey];
        NSUInteger was = [bar.items indexOfObject:wasItem];
        // The same is true for the new tabBarItem but it will be under the "new" key.
        UITabBarItem *isItem = [change objectForKey:NSKeyValueChangeNewKey];
        NSUInteger is = [bar.items indexOfObject:isItem];
        NSLog(@"was tab %i",was);
        NSLog(@"is tab  %i",is);
    } 
    // handle other observings.
}

Remember to remove yourself as observer in both viewDidUnload and dealloc, since viewDidUnload may never be called.

Upvotes: 5

Bernd Rabe
Bernd Rabe

Reputation: 790

Why not storing the lastSelectedIndex in an iVar and in - (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController you have both values on your hands. You might even (never tried it) use - (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController so you have the currently selected view controller index view selectedIndex and then via an additional method you can find the index of the to be selected index of the viewController.

Upvotes: 0

Neo
Neo

Reputation: 2807

There may be better ideas but one way to do is by by creating a NSString object in your AppDelegate to store the name of the class of the current view controller so that you can read the string from your next view controller and check the previously selected item.

In you AppDelegate.h declare a string and synthesize it.

@property (strong, nonatomic) NSString * preSelectedViewController;

And in all your UIViewControllers which are set as items for your UITabViewController do this

in .h files

#import "AppDelegate.h"

in .m files include this in your viewWillAppear: method

AppDelegate * delegate1 =(AppDelegate *) [[UIApplication sharedApplication] delegate];
if (delegate1.preSelectedViewController ==nil) 
{
    delegate1.preSelectedViewController=NSStringFromClass( [self class]);

}

NSLog(@"previous %@",delegate1.preSelectedViewController);

//include 2nd_viewcontroller.h file and this if statement in your 3rd_viewcontroller(i.e. where you want to check and do your other programming) 
if ([delegate1.preSelectedViewController isEqualToString:NSStringFromClass([2nd_ViewController class]) ]) {
    //do your little extra code
}

delegate1.preSelectedViewController=NSStringFromClass( [self class]);
NSLog(@"present %@",delegate1.preSelectedViewController);

Guess this will work for you

Upvotes: 0

rdelmar
rdelmar

Reputation: 104082

I don't know if this can be done in a way other than what you suggested (a state variable), if you're not using a UITabBarController. If you are using a tab bar controller, then you can do this in the delegate of the tab bar controller:

- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController {
    if (viewController == [self.tabBarController.viewControllers objectAtIndex:2 && self.tabBarController.selectedIndex == 1]) {
        NSLog(@"Do special programming");
    }
    return YES;
}

This method is called before the switch is made (unlike the UITabBar method didSelectTabBarItem), so the selected index will be the index of the tab that was active before you touched the new tab.

Upvotes: 2

Related Questions