Archives for category: UITabBarController


Last week WordPress founding developer Matt Mullenweg was interviewed by John Battelle at SXSW where he was startlingly candid about the shortcomings of WordPress’s iPhone app

“Twitter inspired us to start taking mobile seriously,” he added. “You open it [Twitter’s app] at any time and instantly start reading your friends’ tweets. If you open our app you get a blank screen.”
Mullenweg was startlingly candid about the shortcomings of WordPress’s iPhone app, which he described as “not good yet.” His engineers are working to improve it, he added.

Not Good Yet

I’m a big WordPress fan, having used it for years on my personal blog and more recently here on iDevRecipes. I tried the WordPress iPhone app a while back and I’d wholeheartedly agree with Matt that it’s “not good yet.”

Now just as Matt said, the WordPress Mobile team is working on it. Just yesterday, they released version 2.7 of the app with over 100 bug fixes and UI improvements like pull to refresh.

Making it Great

But Matt’s comments got me thinking on how to make the WordPress app really great. Most iPhone apps initially focus on content consumption with a splash of account management. The thinking is that users are much more likely to consume on these devices.

The WordPress app is actually open sourced and you can see that it uses the WordPress XML-RPC API which predated the iPhone to let you manage your blog.

I think this XML-RPC API nudged the WordPress iPhone app towards a full blown account management app. But where is the content consumption? (reading the comments on your posts doesn’t count!)

Reimagined Around Content Consumption

So my first thought was to reimagine the app around content consumption. WordPress.com has a bunch of great curated content. They highlight posts in their Freshly Pressed section and they categorize blogs based on tags.

A little sketching, thinking and poking around WordPress.com and here is what I came up with:

  • First convert the app to a tab based app
  • Fill the first tab with the Freshly Pressed content
  • Fill the second tab with Tags, letting you explore the tags and then see blogs associated with each tag
  • In the third tab put Posts I like. You’d be able to add to this list either on WordPress.com or by liking posts from within the app
  • In the fourth tab put Subscriptions, letting you see the newest posts from the blogs that you subscribe to (Subscriptions are like RSS feeds for non-techies)
  • Take the existing app and put it under a My Blogs tab at the end of the tab bar

Prototype Implementation

Of course this is an iOS development blog, and we can’t have a post without code! So I implemented the first two items in the list. Using our previous Twitter custom tab bar recipe I converted the main view of the app to be tab bar based app. Next I added the Freshly Pressed content to the first tab.

Freshly Pressed

Normally when displaying existing content in an iPhone app, you can’t go wrong with RSS feeds. Freshly Pressed has an RSS feed, but it just displays the first page of content. Also, the image for each featured post is offset using a background-position CSS property that the RSS feed doesn’t expose.

Scraping

So I did what seemed reasonable at the time: I wrote a ruby script that scraped the Freshly Pressed pages and put some JSON up on S3. Now keep in mind that we’re just experimenting here and we can easily swap this scraping out for a real Freshly Pressed API.

Some interesting things about the ruby script: The images uses either a WordPress image server to resize the original images or an imgpress WordPress service to convert the blog home page to an image, and in both cases I change the width from the 223 pixels the web site uses to 320 pixels so the images look nice on the iPhone. After increasing the size from 223 to 320, I also have to increase the pixel offset for each image. For example, if the offset was -30 pixels for the original image, then the offset for the new image is -30 * (320/223).

Without a real design, my first cut iteration of the table view cells is to mirror the look of the web site, including the colors, fonts and general layout

Tapping on each cell loads the blog post in a UIWebView

What do you think?

If you were to imagine a really great WordPress iPhone app, what would you come up with?
Are there things about this design/implementation you like/don’t like?

Let me know in the comments!

Full Source code: https://github.com/boctor/idev-recipes/tree/master/WordPressReimagined

Tweet This!Hacker NewsShare on Facebook

Advertisements

Full Source code: https://github.com/boctor/idev-recipes/tree/master/CustomTabBarNotification

Problem:

When the Instagram app wants to let you know that you have new comments, likes or followers, it doesn’t use standard badge values on tab bar items:

Instead it uses a custom tab bar notification view. How do we build a similar custom notification view?

Solution:

Just like in our recipe for the Twitter app’s current tab bar indicator we will add a view on top of the tab bar to notify the user. Instead of a static image, we will add a slightly more complicated view. This view has the background, icons for each of the activities (comments, likes, followers), and labels with the number value of each of these activities. Here is what it looks like laid out in the NIB:

Vertical/Horizontal Location

Again we need to figure out the horizontal and vertical location of our custom view and we essentially do the same thing we did in our Twitter tab bar indicator recipe:

To calculate the vertical location, we start at the top of the tab bar (0), go up by the height of the notification view, then go up another 2 pixels so our view is slightly above the tab bar

For the horizontal location we divide the width of the tab bar by the number of items to calculate the width of a single item. We then multiply the index by the width of single item and add half the width of an item to land in the middle.

Showing/Hiding the custom notification view

In a real app we would hit a web service, get the data and then notify the user by showing the custom notification UI.

In the sample app we have a couple of buttons that show and hide the notification view. We also do a very simple fade in/fade out animation of the notification view.

Showing the custom notification view:

- (void) showNotificationViewFor:(NSUInteger)tabIndex
{
  // To get the vertical location we start at the top of the tab bar (0), go up by the height of the notification view, then go up another 2 pixels so our view is slightly above the tab bar
  CGFloat verticalLocation = - notificationView.frame.size.height - 2.0;
  notificationView.frame = CGRectMake([self horizontalLocationFor:tabIndex], verticalLocation, notificationView.frame.size.width, notificationView.frame.size.height);

  if (!notificationView.superview)
    [self.tabBar addSubview:notificationView];

  notificationView.alpha = 0.0;

  [UIView beginAnimations:nil context:nil];
  [UIView setAnimationDuration:0.5];
  notificationView.alpha = 1.0;
  [UIView commitAnimations];
}

Hiding the custom notification view:

- (IBAction)hideNotificationView:(id)sender
{
  [UIView beginAnimations:nil context:nil];
  [UIView setAnimationDuration:0.5];
  notificationView.alpha = 0.0;
  [UIView commitAnimations];
}

In the end the solution is quite simple: A custom view laid out in a NIB, added to the view hierarchy at the right location. But it definitely looks sexier than the built in red badge.

What do you think? Can you make this code better? Let us know in the comments!

Full Source code: https://github.com/boctor/idev-recipes/tree/master/CustomTabBarNotification

Tweet This!Hacker NewsShare on Facebook

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

Problem:

The Twitter iPhone App has a custom tab bar that is shorter than the standard tab bar, doesn’t have titles for the tab bar items and has a blue glow indicating when a section has new content. We want to recreate this custom tab bar.

Solution:

Just like segmented controls, the best way to customize the tab bar is to build it from scratch. In fact we’re going to start by using a recipe similar to what we used for custom segment controls:

  • Create a button for every tab bar item.
  • Manage the touches on the buttons so when one is selected, the others are deselected.

But how do we recreate the look of the buttons and how about that nice background for the tab bar?

The tab bar background

Looking at the images of the Twitter app, we find the TabBarGradient.png image which is 22px, exactly half the 44px height of this custom tab bar.

Taking a screenshot of the Twitter app and looking at it carefully reveals how the background is built:

  • The top half is a stretchable image of TabBarGradient.png
  • The bottom half is simply solid black

The custom tab bar asks its delegate for the background image and here is how we build it:

// Get the image that will form the top of the background
UIImage* topImage = [UIImage imageNamed:@"TabBarGradient.png"];

// Create a new image context
UIGraphicsBeginImageContextWithOptions(CGSizeMake(width, topImage.size.height*2), NO, 0.0);

// Create a stretchable image for the top of the background and draw it
UIImage* stretchedTopImage = [topImage stretchableImageWithLeftCapWidth:0 topCapHeight:0];
[stretchedTopImage drawInRect:CGRectMake(0, 0, width, topImage.size.height)];

// Draw a solid black color for the bottom of the background
[[UIColor blackColor] set];
CGContextFillRect(UIGraphicsGetCurrentContext(), CGRectMake(0, topImage.size.height, width, topImage.size.height));

// Generate a new image
UIImage* resultImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

return resultImage;

The buttons

The buttons have the following visual states:

  • Drawn in gray when unselected
  • Drawn with blue gradient when selected
  • Embossed border is drawn around the selected item

A button has both an image and a background image and they can both be set for the various control states. When a button is selected, the blue gradient appears to be on top and the embossed border is behind it. So here is how we’ll setup the button:

  • The button’s image for the normal state will be gray
  • The button’s image for the selected/highlighted state will be blue
  • The button’s background image for the selected/highlighted state will be the embossed border

The images for the tab bar items

A standard UITabBar only uses the alpha values of the tab bar item images. It doesn’t matter what color the images are, they will always appear in gray and blue. For our custom tab bar to be truly reusable, it will need to do the same thing.

But how exactly do we do this? It takes several steps:

  1. First we take the image and use CGContextClipToMask to generate a new image that has a white background and black content:
  2. Next we take this black and white image and use CGImageMaskCreate to create an image mask.
  3. Finally we combine the image mask with a background color.

For every tab bar item we generate two images: one with a solid gray background and another with a blue gradient background.

The blue glow

The blue glow is an image that is simply added to each button as a subview. In the Twitter app, a tab bar item will get a blue glow after the app has downloaded new content. It is a visual cue that there is more content in that section.

Our custom tab bar asks its delegate for the glowImage and it exposes a couple of methods to manage the glow: glowItemAtIndex and removeGlowAtIndex.

The current tab bar indicator

When a tab bar item is selected, a triangle at the top of the tab bar animates into place. We covered this animation in an earlier post. We use the code from that post to get the same animation for the custom tab bar.

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

Tweet This!Hacker NewsShare on Facebook

Full Source code: https://github.com/boctor/idev-recipes/tree/master/TabBarAnimation

Problem:

The Twitter iPhone App has a small arrow indicator above the tab bar that animates when a tab is selected. We want to recreate this animation.





Solution:

The arrow is simply another image added on top of the tab bar which is animated every time the tab selection changes. So we have two tasks:

  • Add the arrow on top of the tab bar. This is similar to what we did in our last recipe.
  • Animate the arrow when a new tab is selected.

To add arrow on top of the tab, we have to figure out the proper horizontal and vertical locations.

Vertical Location

The vertical location is always the same so we’ll figure it out just once. To calculate the vertical location, we start at the bottom of the window, go up by height of the tab bar, go up again by the height of arrow and then come back down 2 pixels so the arrow is slightly on top of the tab bar:

CGFloat verticalLocation = self.window.frame.size.height - tabBarController.tabBar.frame.size.height - tabBarArrowImage.size.height + 2;

Horizontal Location

The horizontal location will change depending on which tab bar is currently selected. So we’ll write a method that given a tab index figures out the horizontal location.
There is nothing too complicated here: We divide the width of the tab bar by the number of items to calculate the width of a single item. We then multiply the index by the width of single item and add half the width of an item so the arrow lands in the middle:

- (CGFloat) horizontalLocationFor:(NSUInteger)tabIndex
{
  // A single tab item's width is the entire width of the tab bar divided by number of items
  CGFloat tabItemWidth = tabBarController.tabBar.frame.size.width / tabBarController.tabBar.items.count;
  // A half width is tabItemWidth divided by 2 minus half the width of the arrow
  CGFloat halfTabItemWidth = (tabItemWidth / 2.0) - (tabBarArrow.frame.size.width / 2.0);

  // The horizontal location is the index times the width plus a half width
  return (tabIndex * tabItemWidth) + halfTabItemWidth;
}

Add the arrow on top of the tab bar

On app startup we add the arrow on top of the selected tab. Our sample app doesn’t remember which tab you had selected before you quit, so we always start at index 0 ([self horizontalLocationFor:0]):

- (void) addTabBarArrow
{
  UIImage* tabBarArrowImage = [UIImage imageNamed:@"TabBarNipple.png"];
  self.tabBarArrow = [[[UIImageView alloc] initWithImage:tabBarArrowImage] autorelease];
  // To get the vertical location we start at the bottom of the window, go up by height of the tab bar, go up again by the height of arrow and then come back down 2 pixels so the arrow is slightly on top of the tab bar.
  CGFloat verticalLocation = self.window.frame.size.height - tabBarController.tabBar.frame.size.height - tabBarArrowImage.size.height + 2;
  tabBarArrow.frame = CGRectMake([self horizontalLocationFor:0], verticalLocation, tabBarArrowImage.size.width, tabBarArrowImage.size.height);

  [self.window addSubview:tabBarArrow];
}

Animate the arrow when a new tab is selected

A UITabBarController delegate gets notified every time a view controller was selected. We’ll use this as the trigger for starting the animation.

The actual animation is very simple. We use animation blocks available on every view.

If you haven’t used animation blocks before, here is a simple description:

  • Before you start the animation block set the frame of the item you want to animate to the start location.
  • Inside the animation block set the frame of the item you want to animate to the end location.

That’s all you have to do. The OS figures out the intermediate frames and does the actual animation for you. Doesn’t get simpler than that.

The arrow is already at the location we want it to animate from, so we don’t have to do anything before we start the animation block.

Inside the animation block block, all we have to do is set the final location of the arrow. So we take the existing frame of the arrow and change its horizontal location based on the newly selected tab index:

- (void)tabBarController:(UITabBarController *)theTabBarController didSelectViewController:(UIViewController *)viewController
{
  [UIView beginAnimations:nil context:nil];
  [UIView setAnimationDuration:0.2];
  CGRect frame = tabBarArrow.frame;
  frame.origin.x = [self horizontalLocationFor:tabBarController.selectedIndex];
  tabBarArrow.frame = frame;
  [UIView commitAnimations];
}

There a couple of things you can play around with to customize the animation:

  • The value you pass to setAnimationDuration will speed up or slow down the animation.
  • You can also set an animation curve. The default curve is UIViewAnimationCurveEaseInOut which causes the animation to start slowly, get faster in the middle and then slow before the animation is complete. Other curves like UIViewAnimationCurveEaseIn cause the animation to start slowly and then get faster until completion.

Full Source code: https://github.com/boctor/idev-recipes/tree/master/TabBarAnimation

Tweet This!Hacker NewsShare on Facebook

Full Source code: https://github.com/boctor/idev-recipes/tree/master/RaisedCenterTabBar

Problem:

Apps like Instagram, DailyBooth and Path™ have what looks like a standard UITabBarController, but the center tab bar is raised or colored. How do we recreate this look?


Solution:

These tab bars look pretty standard with the exception of the center item, so we’ll start out with a standard UITabBarController which contains a UITabBar.

Looking at the images inside each app, it is quickly apparent that the middle tab bar is simply a custom UIButton.

A UITabBar contains an array of UITabBarItems, which inherit from UIBarItem. But unlike UIBarButtonItem that also inherits from UIBarItem, there is no API to create a UITabBarItem with a customView.

So instead of trying to create a custom UITabBarItem, we’ll just create a regular one and then put the custom UIButton on top of the UITabBar.

Our basic recipe is then to create a subclass of UITabBarController and add a custom UIButton on top of the UITabBar.

If the button is the same height as the UITabBar, then we set the center of the button to the center of the UITabBar. If the button is slightly higher, then we do the the same thing except we adjust the center’s y value to account for the difference in height.

UIButton* button = [UIButton buttonWithType:UIButtonTypeCustom];
button.frame = CGRectMake(0.0, 0.0, buttonImage.size.width, buttonImage.size.height);
[button setBackgroundImage:buttonImage forState:UIControlStateNormal];
[button setBackgroundImage:highlightImage forState:UIControlStateHighlighted];

CGFloat heightDifference = buttonImage.size.height - self.tabBar.frame.size.height;
if (heightDifference < 0)
  button.center = self.tabBar.center;
else
{
  CGPoint center = self.tabBar.center;
  center.y = center.y - heightDifference/2.0;
  button.center = center;
}

[self.view addSubview:button];

You might notice that in the code we don’t add the button as a subview in viewDidLoad. This is because we have our UITabBarControllers within a UINavigationController. When viewDidLoad is called, our UITabBarController’s view is the entire height of the screen. If we add the button as a subview in viewDidLoad we’d have to manually account for the navigation bar or properly setup the button’s autoresizingMask both of which complicate the code. But after the UITabBarController is pushed onto the UINavigationController stack, the UITabBarController’s view is auto resized to account for the navigation bar. So we delay adding the button as a subview until the UITabBarController’s has been pushed onto the UINavigationController stack. We do this by registering for the navigationController’s willShowViewController callback.

Full Source code: https://github.com/boctor/idev-recipes/tree/master/RaisedCenterTabBar

Tweet This!Hacker NewsShare on Facebook