How To Make An Interface With Horizontal Tables Like The Pulse News App: Part 1

This is a blog post by iOS Tutorial Team member Felipe Laso, an independent iOS developer and aspiring game designer/programmer. In this 2-part series you’ll learn how to make an interface similar to the Pulse News app for iPhone and iPad by using only UITableViews. Here are some of the things we’ll focus on for […] By Ray Wenderlich.

Leave a rating/review
Save for later
Share
You are currently viewing page 4 of 5 of this article. Click here to view the first page.

Some Visual Tweaks

Before wrapping up this first part, let’s make a few visual adjustments so we make our app look nicer and more in line with the final design. First up is a custom image for our navigation bar. The height for the navigation bar both on iPhone and iPad is 44 pixels, and for the Retina Display it’s 88 pixels high.

I have created a couple of custom navigation bars for our app (which is now called Raze News), which you’ll find in the resources for this project you downloaded earlier in the NavBar folder.

Add them to your project in the corresponding folders (the navigation bars for iPhone under Images in the iPhone/Images folder and the iPad navigation bar in the iPad/Images folder).

With the navigation bar images in place, let’s go ahead and customize the toolbar. Open up the HorizontalTablesAppDelegate.m file and add this above the implementation of the delegate:

@implementation UINavigationBar (UINavigationBarCustomDraw)

- (void)drawRect:(CGRect)rect
{
    [[UIImage imageNamed:@"NavBar.png"] drawInRect:rect];
    self.topItem.titleView = [[[UIView alloc] init] autorelease];
    
    self.tintColor = [UIColor colorWithRed:0.6745098 green:0.6745098 blue:0.6745098 alpha:1.0];
}

@end

What this is doing is creating a Category for the UINavigationBar class, this means that we can add methods or override methods without having to subclass UINavigationBar.

All we do here is create an image with the name of the standard image and draw it in the navigation bar’s rect (if the app is being used on a Retina enabled device it will load the “@2x” image, and if it’s being loaded on iPad it will load the image with the “~iPad” at the end of the file name).

We then set the title of the navigation bar to an empty UIView, that’s so we don’t have a title on top of our custom image. And finally we set the tint color to the same gray we use for the background, this way the buttons on our navigation bar will have the same tint.

Keep in mind that there is a much better way of doing this in iOS5, but we can’t discuss here yet due to the NDA. All I can say is stay tuned for Steve Baranski’s killer tutorial on the subject! :]

Well that was simple huh? And the best part is that it will work throughout our entire application, meaning modal views, the mail composer as well as sub-view controllers we create.

Go ahead and run your project, this is what it looks like now:

Custom navigation bar on the iPhone

We are extra happy! :D But things still look a bit off, let’s take care of that right now.

One trick i discovered while working on this app is that on the iPhone we can have the Status Bar (which displays connection strength, battery life, etc.) with a custom tint color, it makes the app look gorgeous. Unfortunately this does not work on the iPad.

In your Project Navigator go to the HorizontalTables-Info.plist file under the Supporting Files folder. Add a line at the end of the file and for the key value search for Status Bar Style. Once that is selected for the value select Transparent Black Style (alpha of 0.5). This is what my info.plist file looks like:

Customizing status bar style in Info.plist

But if you run the app it still has a black Status Bar, which isn’t what we want. Open up the MainWindow_iPhone.xib file and in the Interface Dock select the Window object, now in the attributes inspector change the background color to these RGB values:

  • Red: 0
  • Green: 207
  • Blue: 109

It’s not the same green as the title in our navigation bar, but because the Status Bar is black with an alpha of 0.5 it will look just like our title color.

Customizing status bar color by changing Window background color

Make these changes on the MainWindow_iPad.xib file as well, even if the status bar won’t show it our app will be future proof in case Apple changes the Status Bar style on iPad.

Run the app and check out the Status Bar color:

Customizing the status bar color on the iPhone

Niiiiiiiiice, it’s a very subtle effect that makes our app look even better.

We are triple happy now! :] :] :]

The final thing we are going to do is customize our table view’s section headers so they too match the look of our app. This is very simple since the UITableViewDataSource provides us with a way to establish the height for each header as well as give it a custom UIView.

Open up the ArticleListViewController_iPhone.m file and add the following code:

#define kHeadlineSectionHeight  26
#define kRegularSectionHeight   18

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
    return section == 0 ? kHeadlineSectionHeight : kRegularSectionHeight;
}

That’s just like an if-else statement wrapped up in a single line. As an interesting tip it’s the only ternary operator available in C. The values used here can be changed to whatever you like, I found these to look good on the app but feel free to customize those as well. We declared some defines because we used these values a few times whilst customizing our headers, if you decide to change the height it will be quite easy coming in and changing the values just once.

Jump over to the ArticleListViewController_iPad.m file and add the following code:

#define kHeadlineSectionHeight  34
#define kRegularSectionHeight   24

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
    return section == 0 ? kHeadlineSectionHeight : kRegularSectionHeight;
}

Again these are just values that look good on the iPad, they can be anything you like.

Now in order to customize the section header we have to add another method from the table view data source. Go over to the ArticleListViewController_iPhone.m file and add the following code:

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    UIView *customSectionHeaderView;
    UILabel *titleLabel;
    UIFont *labelFont;
    
    if (section == 0)
    {
        customSectionHeaderView = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, tableView.frame.size.width, kHeadlineSectionHeight)] autorelease];
        
        titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 0, tableView.frame.size.width, kHeadlineSectionHeight)];
        labelFont = [UIFont boldSystemFontOfSize:20];
    }
    else
    {
        customSectionHeaderView = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, tableView.frame.size.width, kRegularSectionHeight)] autorelease];
        
        titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 0, tableView.frame.size.width, kRegularSectionHeight)];
        
        labelFont = [UIFont boldSystemFontOfSize:13];
    }  
    
    customSectionHeaderView.backgroundColor = [UIColor colorWithRed:0 green:0.40784314 blue:0.21568627 alpha:0.95];
    
    titleLabel.textAlignment = UITextAlignmentLeft;
    [titleLabel setTextColor:[UIColor whiteColor]];
    [titleLabel setBackgroundColor:[UIColor clearColor]];   
    titleLabel.font = labelFont;
    
    NSSortDescriptor* sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:nil ascending:YES selector:@selector(localizedCompare:)];
    NSArray* sortedCategories = [self.articleDictionary.allKeys sortedArrayUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];
    
    NSString *categoryName = [sortedCategories objectAtIndex:section];
    
    titleLabel.text = [categoryName substringFromIndex:1];
    
    [customSectionHeaderView addSubview:titleLabel];
    [titleLabel release];
    
    return customSectionHeaderView;
}

Don’t be scared, let’s step through each portion of code to see what it does. First we create a UIView, UILabel and UIFont for our custom header.

if (section == 0)
    {
        customSectionHeaderView = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, tableView.frame.size.width, kHeadlineSectionHeight)] autorelease];
        
        titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 0, tableView.frame.size.width, kHeadlineSectionHeight)];
        labelFont = [UIFont boldSystemFontOfSize:20];
    }
    else
    {
        customSectionHeaderView = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, tableView.frame.size.width, kRegularSectionHeight)] autorelease];
        
        titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 0, tableView.frame.size.width, kRegularSectionHeight)];
        
        labelFont = [UIFont boldSystemFontOfSize:13];
    }  

This section creates a header with a different height and font size depending on whether it’s the headlines section or just a regular section. We initialize our UIView and UILabel with the same width of the table view and with the height specified earlier in our defines, finally the font size is set according to the category.

customSectionHeaderView.backgroundColor = [UIColor colorWithRed:0 green:0.40784314 blue:0.21568627 alpha:0.95];
    
    titleLabel.textAlignment = UITextAlignmentLeft;
    [titleLabel setTextColor:[UIColor whiteColor]];
    [titleLabel setBackgroundColor:[UIColor clearColor]];   
    titleLabel.font = labelFont;

What that out of the way, we change the background color of our custom view and set some properties on the UILabel like the text alignment, text color, background color as well as the font to use.

 NSSortDescriptor* sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:nil ascending:YES selector:@selector(localizedCompare:)];
    NSArray* sortedCategories = [self.articleDictionary.allKeys sortedArrayUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];
    
    NSString *categoryName = [sortedCategories objectAtIndex:section];
    
    titleLabel.text = [categoryName substringFromIndex:1];
    
    [customSectionHeaderView addSubview:titleLabel];
    [titleLabel release];
    
    return customSectionHeaderView;

And last but not least we just get the current category title for the section just like we did earlier on the titleForHeaderInSectionMethod. Speaking of which, we don’t need that method anymore so jump over to the ArticleListViewController.m file and delete that method which we wrote earlier.

Go ahead and paste the following code in the ArticleListViewController_iPad.m file:

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    UIView *customSectionHeaderView;
    UILabel *titleLabel;
    UIFont *labelFont;
    
    if (section == 0)
    {
        customSectionHeaderView = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, tableView.frame.size.width, kHeadlineSectionHeight)] autorelease];
        
        titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 0, tableView.frame.size.width, kHeadlineSectionHeight)];
        labelFont = [UIFont boldSystemFontOfSize:26];
    }
    else
    {
        customSectionHeaderView = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, tableView.frame.size.width, kRegularSectionHeight)] autorelease];
        
        titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 0, tableView.frame.size.width, kRegularSectionHeight)];
        
        labelFont = [UIFont boldSystemFontOfSize:20];
    }  
    
    customSectionHeaderView.backgroundColor = [UIColor colorWithRed:0 green:0.40784314 blue:0.21568627 alpha:0.95];
    
    titleLabel.textAlignment = UITextAlignmentLeft;
    [titleLabel setTextColor:[UIColor whiteColor]];
    [titleLabel setBackgroundColor:[UIColor clearColor]];   
    titleLabel.font = labelFont;
    
    NSSortDescriptor* sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:nil ascending:YES selector:@selector(localizedCompare:)];
    NSArray* sortedCategories = [self.articleDictionary.allKeys sortedArrayUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];
    
    NSString *categoryName = [sortedCategories objectAtIndex:section];
    
    titleLabel.text = [categoryName substringFromIndex:1];
    
    [customSectionHeaderView addSubview:titleLabel];
    [titleLabel release];
    
    return customSectionHeaderView;
}

This method is exactly the same as the iPhone method, the only change is the font size being used. This might seem silly right now, but this means the app is ready to have unique interfaces depending on each device.

Say you wanted to use images as backgrounds for the section header, perhaps different font types for each devices, colors, etc., this means it’s ready to be implemented and we avoid filling up our code with if statements for each device family.

We are being clean and making our code easier to change in the future. Should Apple launch an iPhone Nano in the future, all you have to do is write a custom subclass for this device, nothing is broken and no large if statements are put in your methods.

Go ahead and run your project, this is what it looks like:

Final project for this part of the tutorial!

Awesome… Now we are fully happy and joyful!!! :D

Contributors

Over 300 content creators. Join our team.