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.

Does the Internet Devalue Everything It Touches?

Does the Internet Devalue Everything It Touches?

My wife and I spoke at length yesterday about how seemingly the Internet devalues everything it touches.

Zero friction.  Free news.  Ninety-nine cent songs and applications.

Instant gratification at zero cost.

My business continually responds to customers wanting “steak” application features, but coming to the table with “baloney” budgets.

This has really always been the case, but the signal-to-noise between serious-minded buyers and buyers wanting everything-for-nothing is beginning to get deafening.

Regardless of what our perceptions are being trained up to be, delivering quality content of any stripe – performance, applications, knowledge, entertainment – was developed, incubated, curated, and executed – at a cost.

In most cases, significant cost.

And yet the perception in the marketplace of the interwebs is that there is always a free solution to any problem.  Or at least a solution that one can pay someone next to nothing to solve.

Expecting premium service, zero defects, and 100% uptime.

There will come a point when we collectively look around, and wonder where all the professionals went.

Why all we see and consume is substandard and shoddy.

Why the only stores that remain open in our towns are Walmarts, Home Depots, and Best Buys.

Don’t look now, but you’re soaking in it.

Business Etiquette DOES Matter

Business Etiquette DOES Matter

I realize that people are being asked to “do more with less” these days.

That doesn’t mean that common courtesy and business etiquette are no longer required to do your jobs.

It’s more important now than ever before.

  • It doesn’t cost anything to smile or be friendly.  It doesn’t cost anything to say “please” or “thank you.”
  • For any business call, return the call in a reasonable period of time.  Twenty-four hours is reasonable.  A week is not.
  • If you initiate a request for pricing and promise a return call, return the call when promised – especially if the answer is “no” so that you’re not dodging follow up calls.  It’s business – people hear “no” all the time.
  • In the middle of a project, don’t go “dark” for weeks on end.  This applies to both ends of the vendor / client relationship.
  • Do what you say you are going to do, when you say you’re going to do it, at the price you said you’d do the work for.
  • Be a person.  Be accountable.  Corollary: Never, ever, say “it’s not my job.”

Maybe being polite is strictly a function of how we are raised as children.  Maybe it’s directly related to our work environment.  Maybe it’s a direct reflection of your “I-just-don’t-give-a-damn” threshold.

Whatever the case may be, being polite, accountable, and timely will set you apart.

Because for all of us making our way in the wilds of this Recession, doing business with courteous companies makes the difficult journey a little more bearable for all involved.

What I’m Thankful For

What I’m Thankful For

Over twenty-three years ago I married my wonderful wife, Melissa.

She has been poor with me, and not-so-poor with me, and every step in between.

We have laughed and cried together.

We’ve enjoyed amazing highs and suffered personal loss together.

In fact, I can say without a doubt every good thing that has ever happened in my life – my career, our sons, being the person I am today – I owe in large part to her.

She is the one truly great decision I’ve made in my life.

And for this I am most thankful.

Child’s Play

Child’s Play

Yesterday I witnessed a fight and a hockey game broke out (rimshot).

No – what really happened was that I got to see how ugly we as parents can become when we take youth sports entirely too seriously.

Prior to the game my son was to play at a rink in Tampa, FL, a couple of kids got into a fight on the ice.  Actually, three kids got into the same fight after some “chippy” play that was allowed to continue with no penalty for a good two periods or so of play.

Before it was all over, several kids were thrown out of the game, as well as a few coaches.

Ugly enough, to be sure.

But it got even worse.

While all of the bruhaha was happening on the ice, some parents in the stands started putting their hands on each other.  And before it was all said and done, three sheriffs deputies were summoned to the rink to remove the people who were fighting in the stands.

What was I doing?

Trying to find my son so that I could make sure he was not in harm’s way.  He had just headed to the locker  room moments before, quite near to the stands where all of the fighting had broken out.  With raw emotions like that out into the open, one never knows what people will do – and I didn’t want him somewhere where he could be “collateral damage” if things went from worse to tragically so.

I found my oldest son, but not before almost being bowled over with my four year old by one of the participants of the fight in the stand (a “lady”) on her way to call the cops.

All this, in the span of about five minutes, at a hockey game for 9 and 10 year old kids.

The ingredients for all of this were several:

  • A pair of refs – one of who was in his late fifties / early sixties – who clearly were letting rough play get out of hand (there is no “checking” at this age of play in travel hockey).
  • A pair of teams were playing who are having non-winning seasons, half-way in, in a physical game tied at 1-1 when all the trouble broke out.
  • A kid that had been “checked” one too many times with no sanction.
  • Coaches that allowed the moment to get the best of them.
  • Parents in the stands who projected the play of their kids on their personal self worth.
  • Forgetting that there is never – NEVER – a justification for one parent putting their hands on another spectator at a children’s sports event.  Period.

I guess I could get all touchy-feely and throw in the stress of the holidays and the economy, too.

But in reality, we as parents often place way too much emphasis on equating the performance of our kids with how others perceive us.

At then end of the day, youth team sports are supposed to teach our kids how to compete fairly, how to prepare physically and mentally, how to play together as a team, and how to be gracious whether winning or losing.

Child’s Play.

Yesterday was anything but Child’s Play.

But it did provide an excellent teachable moment – and sad reminder – that many of us never grow up.

You’d think with all my video game experience that I’d be more prepared for this

You’d think with all my video game experience that I’d be more prepared for this

Well.

I finally got “bit” by the current Apple mania for ferreting out private API calls in App Store iPhone Applications.

You’d think with all my video game experience that I’d be more prepared for this (props to Toy Story 2).

Anywho, these are the two lines of code that got my submission smacked out of the park:

[[UIApplication sharedApplication] terminate];

and

[NSHost currentHost];

Doesn’t look like much, does it?

Still, verboten all the same.

In the case of the terminate function call, all I’m trying to do gracefully end the application in the event that network connectivity is not available.  There is a simple workaround here, and that is to instead use the C Language exit(0) call.  Easy-peazy, lemon-sqeazy.

The second “offending” call, [NSHost currentHost], is simply a call to get the iPhone’s current IP address.  The workaround here is to do something else, like this.

In any event, both of these changes were minor.

But frustrating.

Was I in the “wrong” for using them?  In the view of Apple, absolutely.  And in view of what I agreed to as an iPhone Developer publishing apps on the App Store, again, absolutely.

But, believe it or not, I don’t memorize every API call and know right off the top of my head whether it’s official or not.  Shocking, I know.

And, since the app that was being submitted has been in the App Store for over a year (as have these forbidden calls), it wasn’t like I was trying to sneak in some neato feature available only to Apple by using private calls.

Long story longer, I can easily correct these transgressions – and have done so – in about 15 minutes time.

The bad news is that the app sat in the approval queue for ten (10) days just to be rejected.  An app that has passed numerous times before.  And now must be resubmitted and waited upon.  Again.

Another seven-to-fourteen visit to the purgatory of App Store Approval.

If you think you’re gonna sneak some hidden feature in, reconsider.

Unless, of course, you have all the time in the world to resubmit offending apps.

Living By Your Wits

Living By Your Wits

As someone who ** tries ** to live by my wits (i.e., an entrepreneur), one of the challenges I face as a business person is to convey the sense of urgency I feel in collecting monies owed me.

In good times, the gauche subject of “when do I get paid” is gingerly treated.

In lean times, sometimes it’s hard not to scream it from the rooftops.

For example, in a big company you’re used to the checks getting to your desk on payday before lunch time, so that you can make your deposit during lunch and hope the line at the bank is not too long so that you might be able to score actual food before heading back to the cube farm.

And if it’s not there by lunchtime, SOMEBODY is getting a phone call.

As a small vendor, you sweat calling that customer for the second time in a week asking where the promised check they “mailed” is.

You know – the check you’ve been trying to collect for the past month, trying to remain professionally aloof all the while sweating where the cash for the next payroll is going to come from.

And keeping them as a customer.

And keeping your sanity.

I saw a ridiculous article in Business Week some weeks back, where the “business expert” writing the article gave his best sound advice to a small business person – don’t pay your vendors.

Holy Crap.

No wonder the economy is where it is today, if this is considered sound “advice.”

My biggest struggle this year as a small business person has not necessarily been getting projects or engagements – it has been getting PAID for the work that I have performed, cheerfully and timely.

From customers who are otherwise giving me glowing reviews but are slow to whip out the checkbook.

And the sad thing is, this is happening to many, many of my colleagues who are doing fantastic work – but are having to spend significant time that is not directly related to their passion, just to be paid for the work that they have done; on time, and as asked for.

For many of the small business people I’ve worked with for the past dozen years or so, they have simply given up trying.

So, the next time you think that a vendor is “hounding” you for that check you promised him a few weeks back… please consider what you would do if your paycheck was late four or five weeks – rather than simply an hour or so – on any given payday.

Believe it or not, almost every vendor wants to do what they do best, and not have to speak with your payables department weekly, or even worse, daily – to collect.

Crass?  Gauche?  Unseemly?

Perhaps.

But small vendors can’t pay their bills with “the check’s in the mail.”

Something to think about this Friday at any rate while you’re waiting to beat the bank rush.

Video

And That’s All I’m Gonna Say About That…

If you don’t follow me on Twitter or Facebook, then you don’t know I attended the NASA Tweetup for the launch of Atlantis STS-129.

If you DO happen to follow me, then you’re sick of hearing about it.

So this is my wrap up of the last two days, with just a few parting comments.

  • Having been to a launch before, and having witnessed several from my home in Orlando, I was still taken by surprise at the emotion that swept over me at liftoff.
  • The sound of dozens of car alarms going off after liftoff was funny.
  • It was great seeing folks from where I grew up in Tennessee covering the launch.  Met the media crew from Middle Tennessee State University when we arrived.  Nice to hear people speak “without accents.”
  • NASA went WAY out of their way to accommodate everyone.  The event was very well run and the only real complaint of the two day event was the lack of wireless mics for Q&A with the GREAT speakers – and surprise guests – that we had.
  • Some of the speakers were more self-effacing than anyone would imagine.  And some could stand to be more so (google “Miles O’Brien Drinking Game.”).
  • Dara Torres doesn’t look like the oldest Olympian.  In fact, she is quite hot.

This is what I saw, and what I felt, at the culmination of what we were there for.

And that’s all I’m gonna say about that.

In Flanders Fields

In Flanders Fields

In Flanders Fields
By: Lieutenant Colonel John McCrae, MD (1872-1918)
Canadian Army

In Flanders Fields the poppies blow
Between the crosses row on row,
That mark our place; and in the sky
The larks, still bravely singing, fly
Scarce heard amid the guns below.

We are the Dead. Short days ago
We lived, felt dawn, saw sunset glow,
Loved and were loved, and now we lie
In Flanders fields.

Take up our quarrel with the foe:
To you from failing hands we throw
The torch; be yours to hold it high.
If ye break faith with us who die
We shall not sleep, though poppies grow
In Flanders fields.

iPhone Template

iPhone Template