Underline Text on the iPhone

Underline Text on the iPhone

One of the least talked about feature deficiencies of Apple iPhone SDK Font Handling is the inability to underline text.

You know – like you see in every web link on every web page on the internet.

Yeah.  That.

For me, where I need this the most is when I’m trying to create a link on one of my text sections or display elements, that will invoke a web URI and go off to do some work.

There isn’t a way to style underline fonts included with the iPhone, and Apple doesn’t make it easy at all to include custom fonts without a great deal of pain and gnashing of teeth.

What is one to do?

Well, I don’t know what the rest of you guys do, but this is what I did.

I created a button class (UnderlineButton) that subclasses UIButton and implemented my own drawRect function to draw the underline myself.

This isn’t rocket science, but works quite nicely.  The button should probably have a number of init functions to do things like set underline stroke width and color, but I needed a quick and dirty solution and had about 30 minutes to write, test, and deliver.

The code below is what I wound up with (UnderlineButton.m follows; UnderlineButton.h is simply a stub class that contains only @interface UnderlineButton : UIButton {}).


//
//  UnderlineButton.m
//
//  Created by David Hinson on 11/24/09.
//  Copyright 2009 Sumner Systems Management, Inc.. All rights reserved.
//

#import "UnderlineButton.h"
@implementation UnderlineButton

- (id)initWithFrame:(CGRect)frame {
  if (self = [super initWithFrame:frame]) {
    // Initialization code
    }
  return self;
}
- (void)drawRect:(CGRect)rect {
  [super drawRect:rect];
  CGContextRef context = UIGraphicsGetCurrentContext();

  CGContextSetRGBStrokeColor(context, 62.0/255.0, 62.0/255.0, 62.0/255.0, 1.0);

  // Draw them with a 1.0 stroke width.
  CGContextSetLineWidth(context, 1.0);

  // Draw a single line from left to right
  CGContextMoveToPoint(context, 0, rect.size.height);
  CGContextAddLineToPoint(context, rect.size.width, rect.size.height);
  CGContextStrokePath(context);
}

- (void)dealloc {
  [super dealloc];
}

@end

To use the button in an actual application, you would do something like the following:

  CGSize constraintSize, offset1;
  constraintSize.width  = 300.0f;
  constraintSize.height = MAXFLOAT;

  NSString * btnText = @"My Button Text";

  UnderlineButton * myButton = [[UnderlineButton buttonWithType:UIButtonTypeCustom] retain];
  offset1                    = [btnText sizeWithFont:[UIFont systemFontOfSize:16]
                                constrainedToSize:constraintSize
                                lineBreakMode:UILineBreakModeTailTruncation];
  myButton.frame = CGRectMake(20, 164, offset1.width, offset1.height);
  [myButton setTitle:btnText forState:UIControlStateNormal];

  [myButton setTitleColor:[UIColor darkTextColor] forState:UIControlStateNormal];
  [myButton setFont:[UIFont systemFontOfSize:16]];
  [myButton addTarget:self action:@selector(doButtonTouch:)
            forControlEvents:UIControlEventTouchUpInside];

  [cell myButton];
  [myButton release];

The doButtonTouch method will perform whatever it is you want to do; in my case this invoking another method to slide in a UIWebView to show drill down content.

Summary: Underline Text. Nothing there to make it natively easy, but workable solutions can be cobbled together.

But I will be the very first to say “it shouldn’t be this hard.