Practice Safe Subclassing: NSTableView Row Highlighting

Even though hand crafting source lists are a lost art on Leopard (since the look is now offered natively in AppKit), for cross-developed applications or other styling needs, I’d to demonstrate a safe and sturdy technique for custom drawn NSTableView row highlights.

One seemingly always overlooked fact about NSTableView subclassing is that custom row highlighting can be achieved solely by overriding public, documented methods on 10.4 and above. A decent number of NSTableView subclasses I’ve come across, mainly source list implementations, accomplish customized row highlighting by stepping in the way of the superclass’s normal highlight drawing process by overriding a private and undocumented method called “-_highlightColorForCell.”

As you can imagine, depending on the existence and behavior of a private method is a dangerous line to walk your application along. Such methods have no documented or expected behavior, and more importantly, Apple reserves the right to change or remove parts of the class’s internal implementation as part of any future AppKit framework release.

What I’m focused on is the technique used to circumvent the NSTableView’s normal (superclass defined) row highlighting process. This task is an essential component of any source list style subclass, as we’d like to replace Apple’s highlight with something completely different. The process is actually quite simple; what’s difficult is knowing another approach exists and which methods should be overridden.

So, without further ado, the safe way to bypass the standard highlighting is to introduce an NSCell subclass to accompany your custom NSTableView. Just about all NSTableView row highlighting customizations are source lists, which already necessitate an NSCell derivative anyway.

Here’s how it works:

In your NSCell subclass:

- (NSColor *)highlightColorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
{
// Returning nil circumvents the standard row highlighting.
  return nil;
}

In your NSTableView subclass, the following method can be overridden to perform all custom row highlight drawing:

- (void)highlightSelectionInClipRect:(NSRect)clipRect;

One of the reasons you’d want to put your custom row highlight drawing in the table and not the cell is drawing a contiguous gradient for multiple selections.

That’s it! No private method overriding necessary, so now you can highlight away and sleep better at night. This is tested to work on Tiger and above, but since the above methods have been around since 10.1, the process will likely work on older systems as well. I plan to release a reusable and customizable source list view based on this safer approach in the coming week or so; stay tuned to the feed if you’re interested.

Permalink · Written on: 04-20-08