Shadow offset in custom UITableViewCells (for the inner OCD in you)

Apple has a great example code for drawing fast UITableView using custom, complex UITableViewCells called AdvancedTableViewCells. In the example code, you get three versions and I prefer the one named CompositeSubviewBasedApplicationCell, because it draws your cell as one view, just like Loren Brichter’s Fast Scrolling example.

However, Apple’s example code goes a bit further than Loren’s code and adds example for drawing images, different coloured backgrounds and also has better code for handling highlighted cells in my opinion.

As great as the code is, they left out one small detail that really adds a bit extra to the look of your UITableView, plus I find it makes the text less blurry and easier to read. It only requires a few lines of code for each piece of text you’re drawing. The example code provided is actually from the App Store, which, if you look on your device has the nice white shadow y offset.

Here are the before and after pictures:



Original code:

_highlighted ? [[UIColor whiteColor] set] : [[UIColor blackColor] set];
[ drawAtPoint:CGPointMake(81.0, 22.0) withFont:[UIFont boldSystemFontOfSize:17.0]];

Drawing the shadow:

CGPoint point = CGPointMake(81.0, 23.0);
_highlighted ? [[UIColor clearColor] set] : [[UIColor colorWithWhite:1.0 alpha:0.3] set];
[ drawAtPoint:point withFont:[UIFont boldSystemFontOfSize:17.0]];
point.y -= 1;
_highlighted ? [[UIColor whiteColor] set] : [[UIColor blackColor] set];
[ drawAtPoint:point withFont:[UIFont boldSystemFontOfSize:17.0]];

There are a couple of things to note in the above code. Firstly, I made a CGPoint from the original code and made the Y location one pixel lower. This is because we’re drawing the shadow first, underneath the original text. After the shadow has been drawn, we just tell the point to move up one pixel and the text will be drawn in the original location from the original code.

Second, you’ll need to set the text colours twice. Note that for the shadow, we need to use [UIColor clearColor] so it doesn’t look weird when highlighted. Also, set the alpha low (you need to check with your cell’s background colour), but make sure it’s not too white. It’ll be really subtle, yet noticeable to anyone who appreciate nice UI design.

Of course it doesn’t work with white cells, but if you’re doing any kind of custom UITableViewCell drawing it’s a nice touch. Here’s how I use it in my app:

Translucent UINavigationBar

Apparently, making your UINavigationBar requires a (tiny) bit more code than just:

self.navigationController.navigationBar.barStyle = UIBarStyleBlackTranslucent;

After trying hard to change my UINavigationBar colour, and mostly giving up, I found out you have to set its tintColor to nil.

self.navigationController.navigationBar.tintColor = nil;
self.navigationController.navigationBar.barStyle = UIBarStyleBlackTranslucent;

Getting visual with UITableViews [UPDATED]


I’ve updated the code and pushed it to bitbucket. All the drawing takes place in a separate class and only one subview is added to the cell(s). Again, if you need to add images for every single cell in a large UITableView, you should probably update the code a bit to suit your needs :)

$ hg clone

I am working on an app that lists movie releases and tapping a title will display more details about the selected release in a UITableView. One of the details include number of discs included with the product.

Instead of just writing the number of discs in the detailTextLabel, I thought it would be nice to visualize the number of discs. Where appropriate, it’s always a nice touch to use icons/images to dispay information, instead of just using text:

There’s two things added to the cell: a UIImage and a UILabel with the disc amount and label number updated according to the number of discs in the product.

The example code can of course be used for a lot of things than just display some disc icons and a number. Since they’re subviews, it’s probably not wise to use the code as is for every single cell in a large UITableView. Since I am just displaying the icons in one cell, I do not have any memory issues when using subviews.

You can use any integer for the discCount, in the example project, I just used the row number.

A nice touch is the spacing for the disc and label for every disc. The more discs, the less spacing there is between the images and labels (minus one pixel). You will also notice that when there’s 10 or more discs, I simply write the disc amount in the cell’s detailTextLabel and just add one disc image (without a number label). That makes for easier reading when there’s a large amount of discs.

Let me know if you use the code in your own project! I’d love to hear from you if you make any updates to the code that you’d like to share.

cell.textLabel.text = @"Discs";
UIImage *discIcon = [UIImage imageNamed:@"iconDisc.png"];
int discCount = indexPath.row + 1;
if (discCount < 10) {
    for (int i=0; i) {
        CGRect frame = CGRectMake(83 + (17 – discCount) * i, 11, 24, 27);
        UIImageView *discCellImageView = [[UIImageView alloc] initWithFrame:frame];
        discCellImageView.image = discIcon;
        [cell.contentView addSubview:discCellImageView];
        int discNumber = 1 + i;
        CGRect labelFrame = CGRectMake(86 + (17 – discCount) * i, 8, 24, 27);
        UILabel *discCountLabel = [[UILabel alloc] initWithFrame:labelFrame];
        discCountLabel.textColor = [UIColor darkGrayColor];
        discCountLabel.font = [UIFont systemFontOfSize:8];
        discCountLabel.shadowColor = [UIColor whiteColor];
        discCountLabel.shadowOffset = CGSizeMake(0, 1.0);
        discCountLabel.backgroundColor = [UIColor clearColor];
        discCountLabel.text = [NSString stringWithFormat:@"%d", discNumber];
        [cell.contentView addSubview:discCountLabel];
} else if (discCount >= 10) {
    cell.detailTextLabel.text = [NSString stringWithFormat:@"%d", discCount];
    CGRect frame = CGRectMake(113, 11, 24, 27);
    UIImageView *discCellImageView = [[UIImageView alloc] initWithFrame:frame];
    discCellImageView.image = discIcon;
    [cell addSubview:discCellImageView];

You can download the project here:

Or in Terminal:

$ hg clone

Thanks to Blake for his input and help!