14

I'd like to make an app that uses a UITabBarController that is similar to the one in the Twitter app for iPhone and iPod touch. (Blue light for unread and sliding arrow for switching between content views).

Is there an easy way to do this? Any open source code?

Edit:

I've added a bounty. I'm looking for an answer that works across devices and on iOS 4 and iOS 5.

EDIT:

I've messed with my original code and I found a simple solution. I've added the following check, for iOS 5 in my animation code:

//  iOS 5 changes the subview hierarchy 
//  so we need to check for it here

BOOL isUsingVersionFive = NO;
NSString *reqSysVer = @"5.0";
NSString *currSysVer = [[UIDevice currentDevice] systemVersion];
if ([currSysVer compare:reqSysVer options:NSNumericSearch] != NSOrderedAscending){
    //On iOS 5, otherwise use old index
    isUsingVersionFive = YES;
}

Then, instead of this:

CGFloat tabMiddle = CGRectGetMidX([[[[self tabBar] subviews] objectAtIndex:index] frame]);

... I use this:

CGFloat tabMiddle = CGRectGetMidX([[[[self tabBar] subviews] objectAtIndex:index + (isUsingVersionFive ? 1 : 0)] frame]);

Still holding out on the bounty though, in case I get a chance to find something that works in the answers.

Moshe
  • 57,511
  • 78
  • 272
  • 425

5 Answers5

6

I would create a subclass of the standard UITabBarController and add a couple of subviews for the blue light and the sliding arrow. Shouldn't be too hard to accomplish.

Edit: Here's an idea of some of the stuff that should go in your subclass. I don't even know if this code will compile.

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])) {
        super.delegate = self;
    }
    return self;
}

- (void)viewDidLoad {
    [super viewDidLoad];

    //Create blueLight
    UIImage* img = [UIImage imageNamed:@"blue_light.png"]
    self.blueLight = [[UIImageView alloc] initWithImage:img];
    self.blueLight.center = CGPointMake(320, 460); //I'm using arbitrary numbers here, position it correctly
    [self.view addSubview:self.blueLight];
    [self.blueLight release];

    //Create arrow, similar code.
}

- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController{
    //Put code here that moves (animates?) the blue light and the arrow


    //Tell your delegate, what just happened.
    if([myDelegate respondsToSelector:@selector(tabBarController:didSelectViewController:)]){
        [myDelegate tabBarController:self didSelectViewController:viewController]
    }
}
Rafael Vega
  • 4,575
  • 4
  • 32
  • 50
  • Ok. I'll look into it. Any further info is appreciated. – Moshe Sep 12 '10 at 01:20
  • Great example code, but how would you change the shape of the tab? In the twitter app the top is rounded and the bottom is square. – Conceited Code Sep 15 '10 at 01:13
  • 1
    might want to wrap that in `[UIView beginAnimation]` and `[UIView commitAnimations]` to have it slide around – slf Sep 26 '10 at 15:16
  • I've used this as a starting point - see my edit to the question for an iOS5 update. – Moshe Oct 09 '11 at 14:16
4

Here is how you create the arrow

http://isagoksu.com/2009/development/iphone/fancy-uitabbar-like-tweetie/

And follow Rafael's answer to get the blue light.

Conceited Code
  • 4,517
  • 3
  • 29
  • 32
1

Although an ageing post, I though I would interject with a GitHub project that no one mentioned, they've recreated the Twitter styled tab bar quite well, here is the link:

https://github.com/boctor/idev-recipes/tree/master/CustomTabBar

The project is in the sub folder named "CustomTabBar", more information can be found here:

http://idevrecipes.com/2011/01/04/how-does-the-twitter-iphone-app-implement-a-custom-tab-bar/

Daniel
  • 23,129
  • 12
  • 109
  • 154
1

BCTabBarController is what I based my custom twitter style tab-bar on and it works in iOS 4 and 5: http://pastebin.me/f9a876a6ad785cb0b2b7ad98b1024847

Each tab view controller should implement the following method for the tabs image:

- (NSString *)iconImageName {
    return @"homeTabIconImage.png";
}

(In the App delegate) you would initialize the tab bar controller like so:

self.tabBarController = [[[JHTabBarController alloc] init] autorelease];
self.tabBarController.delegate = self;
self.tabBarController.viewControllers = [NSArray arrayWithObjects:
                                         [[[UINavigationController alloc] initWithRootViewController:[[[iPhoneHomeViewController alloc] init] autorelease]] autorelease],
                                         [[[UINavigationController alloc] initWithRootViewController:[[[iPhoneAboutUsViewController alloc] init] autorelease]] autorelease],
                                         [[[UINavigationController alloc] initWithRootViewController:[[[iPhoneContactInfoViewController alloc] init] autorelease]] autorelease],
                                         [[[UINavigationController alloc] initWithRootViewController:[[[iPhoneMapUsViewController alloc] init] autorelease]] autorelease],
                                         [[[UINavigationController alloc] initWithRootViewController:[[[iPhoneCreditsViewController alloc] init] autorelease]] autorelease],
                                             nil];

Optionally, you can use a custom background image for each tabs view controller with this method:

- (UIImage *)tabBarController:(JHTabBarController *)tabBarController backgroundImageForTabAtIndex:(NSInteger)index {
    NSString *bgImagefilePath;
    switch (index) {
        case 0:
            bgImagefilePath = @"homeBG.png";
            break;
        case 1:
            bgImagefilePath = @"aboutBG.png";
            break;
        case 2:
            bgImagefilePath = @"contactBG.png";
            break;
        case 3:
            bgImagefilePath = @"mapBG.png";
            break;
        case 4:
            bgImagefilePath = @"creditsBG.png";
            break;
        default:
            bgImagefilePath = @"homeBG.png";
            break;
    }
    return [UIImage imageNamed:bgImagefilePath];
}

The arrow at the top of the tab bar slides across to the tab that is selected just like the twitter tab bar.

Some screenshots:

BCTabBarController BCTabBarController

chown
  • 51,908
  • 16
  • 134
  • 170
  • This looks like I need to add code for each tab... Not what I want to have to do. You can probably simplify it by asking the view controller for its tab bar image, no? – Moshe Oct 09 '11 at 01:12
  • @Moshe That is how my version of the BCTabBarController works that I linked at the beginning. The view controller determines each tabs image with the `iconImageName` method. You can _optionally_ put the method (`(UIImage *)tabBarController:(JHTabBarController *)tabBarController backgroundImageForTabAtIndex:(NSInteger)index`) in the app delegate to tell the tab bar controller what image to use as a background image for that tab. – chown Oct 09 '11 at 01:22
  • @Moshe If you do use this code (regardless of who is awarded the bounty) I can help you out with implementing it. Start up a chat if you want any more detailed answers. – chown Oct 09 '11 at 01:34
  • Thanks for the kind offer. At the moment I have a working implementation which works on both, as per my second edit. I'm going to let the bounty run its course, I think, and then add my own complete working code sample. – Moshe Oct 09 '11 at 03:42
  • Actually contacted the developer of this control and ended up not using it as it doesnt implement hidesBottomBarWhenPushed. – barfoon Oct 21 '11 at 17:23
0

Just 2day I made one app like this one for POC, it turns out that it is easier than you can think.

First in my applicationdidfinishlaunching: method I added the imageview holding the image of pointer or arrow with the width as 64 as the screen width is 320 and I have 5 tabs in the tab bar. you can also calculate it if you think that your project will have dynamic tabs and then just change the width of the imageview accordingly something like this.

CGRect rect = tabBarpointerImageView.frame;
rect.size.width = sel.window.frame.size.width / tabbarcontroller.viewControllers.count;
tabBarpointerImageView.frame = rect;

You might also want to set the content mode of that image view as uiviewcontentmodecenter
Also I have set the frame of the imageview by some calculation like this

CGRect rect = CGRectZero;
rect.size.width = self.window.frame.size.width / tabbarcontroller.viewControllers.count;
rect.size.height = 10;// as image was of 10 pixel height.
rect.origin.y = self.window.frame.size.height - 49;// as the height of tab bar is 49
tabBarpointerImageView.frame = rect;

And then in the delegate method of tab bar controller

- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController

just use an animation block to animate the movement of pointer like this

[uiview beginanimation:nil context:nil];
CGRect rect = tabBarpointerImageView.frame;
rect.origin.x = rect.size.width * tabbarcontroller.selectedIndex;
tabBarpointerImageView.frame = rect;
[uiview commitanimations];

PS. Sorry if some spellings are not correct.

Robin
  • 10,011
  • 5
  • 49
  • 75