How To Make An Interface With Horizontal Tables Like The Pulse News App: Part 2
This is a blog post by iOS Tutorial Team member Felipe Laso, an independent iOS developer and aspiring game designer/programmer. This is the second of a two-part series on how to create horizontal table views in an interface similar to the Pulse News App. If you haven’t already, check out part 1 of the tutorial […] By Ray Wenderlich.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
How To Make An Interface With Horizontal Tables Like The Pulse News App: Part 2
50 mins
Testing At Last!
The time has finally come for us, dear readers, to make some tweaks and see our work so far :D
Go over to the HorizontalTableCell_iPhone.m implementation file and add the following import at the top of the file:
#import "ArticleCell_iPhone.h"
We are going to use our custom cell so we need the import. Now go ahead and add the following code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"ArticleCell";
ArticleCell_iPhone *cell = (ArticleCell_iPhone *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[[ArticleCell_iPhone alloc] initWithFrame:CGRectMake(0, 0, kCellWidth, kCellHeight)] autorelease];
}
NSDictionary *currentArticle = [self.articles objectAtIndex:indexPath.row];
cell.thumbnail.image = [UIImage imageNamed:[currentArticle objectForKey:@"ImageName"]];
cell.titleLabel.text = [currentArticle objectForKey:@"Title"];
return cell;
}
All we are doing here is creating a string for the reuse identifier of our article cells, notice we used the same reuse identifier as we did in the ArticleCell class.
After that we create a new ArticleCell_iPhone cell, we use the standard dequeueReusableCellWithIdentifier method provided to us by UITableView, except that it returns a regular UITableViewCell, so we cast it to our custom subclass.
If we don’t get returned a reusable cell we allocate and initialize one with a custom frame that positions it at the very top left corner of its container and makes it the same width and height as our cell.
And in order to set the image and title of our cell we just fetch the current article dictionary from our articles array and set the thumbnail image and article title accordingly.
An interesting thing to mention here is that we already wrote a cellForRowAtIndexPath method back in the ArticleCell class, so why do we do that over there if we just customized it for iPhone right now?
Well because we will get a warning back in ArticleCell.m about an incomplete UITableViewDataSource implementation, so we had to add that there.
Before going on we must change the number of rows in our ArticleListViewController.m file, right now we are returning the number of articles inside each category, we now need a single row because the horizontal table will handle all of the articles.
Go over to ArticleListViewController.m and change the numberOfRowsInSection method to the following:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 1;
}
Now go back to your ArticleListViewController_iPhone.m file and let’s change things a bit so we now use our custom HorizontalTableCell custom class. Add the following imports at the top:
#import "HorizontalTableCell_iPhone.h"
#import "ControlVariables.h"
Next up add the following method:
- (void)awakeFromNib
{
[self.tableView setBackgroundColor:kVerticalTableBackgroundColor];
self.tableView.rowHeight = kCellHeight + (kRowVerticalPadding * 0.5) + ((kRowVerticalPadding * 0.5) * 0.5);
}
This changes the background color of our vertical table and also changes the height of each row so that it can now fit our custom Article Cell.
Finally, replace the code in the cellForRowAtIndexPath method with this one:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"HorizontalCell";
HorizontalTableCell_iPhone *cell = (HorizontalTableCell_iPhone *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[[HorizontalTableCell_iPhone alloc] initWithFrame:CGRectMake(0, 0, tableView.frame.size.width, tableView.frame.size.height)] autorelease];
}
NSSortDescriptor* sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:nil ascending:YES selector:@selector(localizedCompare:)];
NSArray* sortedCategories = [self.articleDictionary.allKeys sortedArrayUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];
NSString *categoryName = [sortedCategories objectAtIndex:indexPath.section];
NSArray *currentCategory = [self.articleDictionary objectForKey:categoryName];
cell.articles = currentCategory;
return cell;
}
This should look pretty familiar, we create a reuse identifier for our cell, try to dequeue one and if that’s not possible we create one. We then sort our categories just like we did in Part 1 of the Tutorial, we get the current category’s array of articles, and instead of fetching a single article, we pass the entire array to our HorizontalTableCell.
That should all that’s necessary for you to run your project now…Go ahead and build and run your project to see what it looks like so far!
This is what I got:
Yay! We have a table that scrolls vertically with horizontal cells embedded within each row that scroll horizontally….AWESOME!
^_^
But there are two things you might have noticed, one is that when we select an article the title label goes clear, and second, if you scroll up and down you might see that the images are repeating and not showing the category’s actual images.
Let’s fix these two things beginning with the label background.
Fixing The Label
The reason why the UILabel becomes transparent when selected has to do with it’s inner workings and how it automatically changes background colors. In order to prevent this we must subclass UILabel and override two very tiny methods for things to work properly.
It might be tedious having all these subclasses but as you have seen there is very little code inside of each one.
Create a new subclass of UILabel under your global Classes folder and name it ArticleTitleLabel. Add this code so your ArticleTitleLabel.h header file looks like this:
#import <UIKit/UIKit.h>
@interface ArticleTitleLabel : UILabel
{
}
- (void)setPersistentBackgroundColor:(UIColor*)color;
@end
We declare a method that will set a persistent background color, that is all. Move on over to the ArticleTitleLabel.m file and delete all of the methods already on it, now add the following two methods and an import for our control variables header file:
// Add to top of file
#import "ControlVariables.h"
// Add new methods
- (void)setPersistentBackgroundColor:(UIColor*)color
{
super.backgroundColor = color;
}
- (void)setBackgroundColor:(UIColor *)color
{
// do nothing - background color never changes
}
- (void)drawTextInRect:(CGRect)rect
{
CGFloat newWidth = rect.size.width - kArticleTitleLabelPadding;
CGFloat newHeight = rect.size.height;
CGRect newRect = CGRectMake(kArticleTitleLabelPadding * 0.5, 0, newWidth, newHeight);
[super drawTextInRect:newRect];
}
When we call setPersistenBackgroundColor all we do is set the UILabel’s background color. Now when it tries calling it’s own setBackgroundColor method we will not do anything, thus preventing the color from changing when selecting our cell.
We override the drawTextInRect method so that the text inside the label can have a little bit of padding on the left and right side, we use the constants created in our ControlVariables.h file to determine the padding and make the label draw it’s text within the newly provided CGRect.
And that’s it, now let’s change the title label from an instance of UILabel to our subclass. Go over to ArticleCell.h and make the following changes:
#import <UIKit/UIKit.h>
// STEP 1
@class ArticleTitleLabel;
@interface ArticleCell : UITableViewCell
{
UIImageView *_thumbnail;
// STEP 2
ArticleTitleLabel *_titleLabel;
}
@property (nonatomic, retain) UIImageView *thumbnail;
// STEP 3
@property (nonatomic, retain) ArticleTitleLabel *titleLabel;
@end
We add a forward declaration for our ArticleTitleLabel class in step 1, in step 2 we change the class of our titleLabel to ArticleTitleLabel and in step 3 we do the same but for our property.
Go to the ArticleCell_iPhone.m file now and make these changes:
- Add this import at the top of your file: #import “ArticleTitleLabel.h”
- Change the line where we create the titleLabel ([UILabel alloc] init]…) to the following: self.titleLabel = [[[ArticleTitleLabel alloc] initWithFrame:CGRectMake(0, self.thumbnail.frame.size.height * 0.632, self.thumbnail.frame.size.width, self.thumbnail.frame.size.height * 0.37)] autorelease];
- Change the line where we change the background color of our label (self.titleLabel.backgroundColor = …) to the following: [self.titleLabel setPersistentBackgroundColor:[UIColor colorWithRed:0 green:0.4745098 blue:0.29019808 alpha:0.9]];
And finally go to HorizontalTableCell_iPhone.m file and add the following import at the top:
#import "ArticleTitleLabel.h"
Go ahead and run your project again, now when you select the Article Cell the background will remain green! Awesome :D