Saturday, October 11, 2008

Cocoa: Notification Badge

I Really like iPhone notifications... a little badge appears on the application's icon and displays something. For example in Apple Mail it displays the number of the unread mails.

Now the Code! a simple method that take an argument that is the number to show on the badge. (IMPORTANT: Take a look at the code, there're appIcon.tiff and starIcon.tiff that you should have in your Project's Resources).
-(void)showNotifyCountOnApplicationIcon: (int) currentCountOfUnread
{
  NSImage *originalIcon = [NSImage imageNamed:@"appIcon.tiff"];
  NSString *countdown = [NSString stringWithFormat:@"%i", currentCountOfUnread];
  NSImage *iconImageBuffer = [originalIcon copy];
  NSSize iconSize = [originalIcon size];

  // Create attributes for drawing the count.
  NSDictionary * attributes = [[NSDictionary alloc]
  initWithObjectsAndKeys:[NSFont fontWithName:@"Helvetica-Bold" size:32],
  NSFontAttributeName, [NSColor whiteColor],
  NSForegroundColorAttributeName, nil];
  NSSize numSize = [countdown sizeWithAttributes:attributes];

  // Create a red circle in the icon large enough to hold the count.
  [iconImageBuffer lockFocus];
  [originalIcon drawAtPoint:NSMakePoint(0, 0)
          fromRect:NSMakeRect(0, 0, iconSize.width, iconSize.height)
          operation:NSCompositeSourceOver
          fraction:1.0f];

  float max = (numSize.width > numSize.height) ? numSize.width : numSize.height;
  max += 28;
  NSRect circleRect = NSMakeRect(iconSize.width - max,
  iconSize.height - max, max, max);

  // Draw the star image and scale it so the unread count will fit inside.
  NSImage * starImage = [NSImage imageNamed:@"starIcon.tiff"];
  [starImage setScalesWhenResized:YES];
  [starImage setSize:circleRect.size];
  [starImage compositeToPoint:circleRect.origin operation:NSCompositeSourceOver];

  // Draw the count in the red circle
  NSPoint point = NSMakePoint(NSMidX(circleRect) - numSize.width / 2.0f + 2.0f,
  NSMidY(circleRect) - numSize.height / 2.0f + 2.0f);
  [countdown drawAtPoint:point withAttributes:attributes];

  // Now set the new app icon and clean up.
  [iconImageBuffer unlockFocus];
  [NSApp setApplicationIconImage:iconImageBuffer];
  [iconImageBuffer release];
  [attributes release];
}

With Mac OS X Leopard was introduced NSDockTile class that lets you customize the visual representation for your application’s miniaturized windows and application icon as they appear in the dock. So with this class you can easily add Notification Badge in this way.
NSDockTile *dockTile = [NSApp dockTile];

// setup our image view for the dock tile
NSRect frame = NSMakeRect(0, 0, dockTile.size.width, dockTile.size.height);
NSImageView *dockImageView = [[NSImageView alloc] initWithFrame: frame];
[dockImageView setImage: [NSImage imageNamed:@"appIcon.tiff"]];

// by default, add it to the NSDockTile
[dockTile setContentView: dockImageView];
[dockTile display];

// Show Notification Badge '45'
[dockTile setShowsApplicationBadge:YES];
[dockTile setBadgeLabel:@"45"];

2 comments:

  1. Hey,
    thanks for the great article.

    I've successfully translated your example to ruby and implemented it in my RSpactor.app.
    http://github.com/rubyphunk/rspactor/tree/bec5c5ea2fa296ab1cc2a6e01a8ff0695a3a9c3b/app/controller/app_controller.rb

    lg // andreas

    ReplyDelete
  2. [...] are used olso in Mac OS X in application like iTunes and in the DockBar, check this post “Cocoa Notification Badge” to see how to use it with [...]

    ReplyDelete