Custom UIButtons via Subclassing

• Chris Liscio

While working on Capo for the iPhone, I had a need for UIButtons that carried custom state. For instance, the dual-state play/pause button which has highlighted variants for each state.

Subclassing UIButton isn't entirely straightforward, so I figured I'd share my approach for getting this to work. Here's the code (Note: Requires the iOS 4.0+ SDK, due to the lack of an ivar!):

There are a few things you need to know about my approach, since I hit some road-blocks while subclassing UIButton on my own.

For starters, you must call setImage:forState: in your chosen initializer, rather than overriding imageForState:. Things won't work if you try and go that route. I think this is because UIButton is accessing the underlying data structure that holds its per-state UIImage instances directly.

Second, it's necessary that you call layoutSubviews to get the button to update its image when you modify its state programmatically. Calling setNeedsDisplay: does nothing, because UIButton likely doesn't do anything in drawRect:.

Finally, you may notice that I asserted against the UIControlStateApplication masks. This is partially because I wanted a record of why I chose the values in the .h file, and partially because I can get some kind of warning in the future if the masks go away (or change.)

Hopefully this helps some of you iOS developers that may be struggling with custom UIButtons!