iPhone Tip: Info Button Woes

Today’s tip is a simple solution to a common problem.  The fix for this problem is all over the internet, but none of the places I visited seemed to give the whole story, they only revealed a piece of the puzzle (sorry for the cliché).  All of us who use the iPhone with any frequency have seen the info button used in onr place or another.  This cute little circle with a lower-case “i” inside is a popular widget used by Apple to denote a way to gain access to details like application settings.

When developers start using this widget in their own code, often two very distinct symptoms pop up instantaneously as soon as they get their app onto a real device:

  1. Often I have to tap the button 3 or more times before it detects the event!
  2. Sometimes (usually when debugging) I tap the button and it recognizes the event seconds later!

This can be a frustrating problem to troubleshoot, especially for a new developer, and is exacerbated by the actual root of the problem…the button is just too darn small!

The Solution

So what do we do about this?  Well, many of us would intuitively try to open up Interface Builder and increase the widget size.  However, Apple has fixed the button’s frame to 18×19 pixels and it cannot be changed through IB.  So for those of us who like to do as much UI layout in IB as possible, we have to roll up our sleeves and write a little code.  Don’t be scared, there isn’t much to it:

The Code

As I mentioned, IB grays out the frame of the Info Button, but it isn’t really a fixed value; you can declare a new frame and apply it to the button in code.  First, choose the amount by which you want to increase the button (I usually use 50 pixels), and let’s call that value “G”.  The following code will shift and grow your frame around the info button.


1
2
3
4
5
CGRect newInfoButtonRect = CGRectMake(infoButton.frame.origin.x-(G/2),
          infoButton.frame.origin.y-(G/2),
          infoButton.frame.size.width+G,
          infoButton.frame.size.height+G);
[infoButton setFrame:newInfoButtonRect];

Code adapted from iPhone SDK Examples.

The Location

So where does this code need to be?  In the UIViewController that handles the button.  I’ve had varying degrees of success putting this code in different methods, but putting it into viewDidLoad: seems to yield the best results.  Don’t forget that the info button must be defined as a property in the UIViewController so we can work with it.  The example below assumes you define your layouts in IB, so the button is also an IBOutlet:

UIViewControllerSubclass.h


1
2
3
4
5
6
@interface ... {
    UIButton *infoButton
}
...
@property (nontatomic,retain) IBOutlet UIButton *infoButton;
@end

UIViewControllerSubclass.m


1
2
3
4
5
6
7
8
...
- (void)viewDidLoad {
    CGRect newInfoButtonRect = CGRectMake(infoButton.frame.origin.x-25, infoButton.frame.origin.y-25,
          infoButton.frame.size.width+50, infoButton.frame.size.height+50);
    [infoButton setFrame:newInfoButtonRect];
    [super viewDidLoad];
}
...

Also, don’t forget to connect the newly created outlet to the Info Button you have defined in IB. With your button’s frame freshly enlarged, give the app another try and see how much easier it is to properly trigger the info button with a real finger!