Wednesday, December 22, 2010

CMPopTipView - a custom popup view for iOS

is a custom iOS UIView that I have released on github.  It is relatively simple, but solved a need I had in an app where I wanted a kind of speech bubble shaped popup to give the user a hint about where to tap next. (You might argue that good UI shouldn't need an extra hint for the user but then I would punch you in the arm and go about my day.)

CMPopTipView is simple to use.  Just initialise it with a target view, a container view and a message to display and it handles positioning itself with the container view to point at the target view, sizing itself to fit the text.  It is also smart about UIBarButtonItems (in either navigation or tool bars) and can position itself properly to point at them. Some example code is shown below.

Some features of CMPopTipView:

  • Automatically positioned in container view;
  • Positions pointer to point at target view (either above or below);
  • Automatically sizes itself to fit the text message;
  • Background and text colours can be customised;
  • User can tap CMPopTipView to dismiss it (with optional delegate callback);
  • Can be dismissed programmatically;
  • Not a modal view.

CMPopTipView draws itself using Core Graphics and so scales up nicely to the high resolution Retina display with no extra work.  It might be a useful reference for iOS developers looking for Core Graphics drawing examples.  The code demonstrates how to draw the path of a custom shape, how to draw a gradient fill within a clipped path, how to apply a shadow to the shape and how to draw text within the shape.

A universal (iPhone/iPad) demo app is included with the source code. It is a button-fest of popup tips, as shown by the screenshots.

Example 1 - point at a UIBarButtonItem in a nav bar:

// Present a CMPopTipView pointing at a UIBarButtonItem in the nav bar
CMPopTipView *navBarLeftButtonPopTipView = [[[CMPopTipView alloc] initWithMessage:@"A Message"] autorelease];
navBarLeftButtonPopTipView.delegate = self;
[navBarLeftButtonPopTipView presentPointingAtBarButtonItem:self.navigationItem.leftBarButtonItem animated:YES];

// Dismiss a CMPopTipView
[navBarLeftButtonPopTipView dismissAnimated:YES];

// CMPopTipViewDelegate method
- (void)popTipViewWasDismissedByUser:(CMPopTipView *)popTipView {
  // Any cleanup code, such as releasing a CMPopTipView instance variable, if necessary

Example 2 - pointing at a UIButton, with custom color scheme:

- (IBAction)buttonAction:(id)sender {
  // Toggle popTipView when a standard UIButton is pressed
  if (nil == self.roundRectButtonPopTipView) {
    self.roundRectButtonPopTipView = [[[CMPopTipView alloc] initWithMessage:@"My message"] autorelease];
    self.roundRectButtonPopTipView.delegate = self;
    self.roundRectButtonPopTipView.backgroundColor = [UIColor lightGrayColor];
    self.roundRectButtonPopTipView.textColor = [UIColor darkTextColor];

    UIButton *button = (UIButton *)sender;
    [self.roundRectButtonPopTipView presentPointingAtView:button inView:self.view animated:YES];
  else {
    // Dismiss
    [self.roundRectButtonPopTipView dismissAnimated:YES];
    self.roundRectButtonPopTipView = nil;

#pragma mark - CMPopTipViewDelegate methods
- (void)popTipViewWasDismissedByUser:(CMPopTipView *)popTipView {
  // User can tap CMPopTipView to dismiss it
  self.roundRectButtonPopTipView = nil;
Get CMPopTipView from github.