Friday, February 17, 2012

Customizing Appearance of Disabled UIBarButtonItems

Have you ever wanted to change the appearance of a disabled UIBarButtonItem? It seems to be a fairly common issue without many good solutions - at least, until iOS 5.0, anyway. Perhaps you've tried this one:

UIBarButtonItem button = 
    new UIBarButtonItem("Untitled 1", UIBarButtonItemStyle.Plain, null);
button.TintColor = UIColor.White;
button.Enabled = false;

It all works fine, up until you disabled the button, at which point your button becomes a very faded version of whatever you had in there. Normally, that's what you want to have happen, because dimming the button is a good indication to the user that the button cannot be pressed at the current time. However, there may be situations where that isn't true...

For example, I have a toolbar with a document title in the center. It's a UIBarButtonItem, so that it can detect touches, and respond by showing a UITextField that allows the document title to be edited. The document editor has two modes: an edit mode, and a run mode. In run mode, I don't want the title to be edited, so I disable the button. However, I still want it to be nice and visible, like a title should be. I also wanted to avoid the obvious workaround of swapping out my title button for another non-functional button with the same content. It would work, but it would kind of break some of the behind-the-scenes stuff we're doing with our user interaction model, and would require me to maintain the state of two separate buttons with the title. Also, a button that is enabled has a little sparkly animation when it is touched, to let you know that it is touchable and that the system recognized that you touched it. The two-button workaround means I would still have that animation, and gives the user the impression that they can still edit the title, but it's not working right.

So, what did I do? Find out after the break.

In iOS 5.0, the UIBarItem class, which is the parent class of UIBarButtonItem, got two new methods:

UITextAttributes GetTitleTextAttributes(UIControlState state);
SetTitleTextAttributes(UITextAttributes attributes, UIControlState state);

If you're using Objective-C, they look like this:

- (NSDictionary *)titleTextAttributesForState:(UIControlState)state
- (void)setTitleTextAttributes:(NSDictionary *)attributes forState:(UIControlState)state

These allow you to get and set the text attributes for a given button state. You can choose from the following states: Normal, Highlighted, Disabled, Selected, Application, and Reserved. The attributes that you are allowed to set are the Font, TextColor, TextShadowColor, and TextShadowOffset. MonoTouch wraps the NSDictionary for these attributes in a UITextAttributes class, which makes it a lot easier to set these, since you don't need to worry about which dictionary key to set and what kind of value it takes. But once you know the keys, it's just as easy to do in Objective-C.

Anyway, since I wanted the disabled state to have white text, let's do that:

var atts = button.GetTitleTextAttributes(UIControlState.Normal);
atts.TextColor = UIColor.White;
button.SetTitleTextAttributes(atts, UIControlState.Disabled);

What I did here is grab the dictionary for the Normal state, tweak the color, and use it to set the Disabled state. Let's see how it looks:

Perfect! Pretty simple, but there's surprisingly little documentation on it out there right now. Remember to use it appropriately - most of the time, your button probably should look disabled.

No comments:

Post a Comment