Huffpost Huffpost Code
THE BLOG

Featuring fresh takes and real-time analysis from HuffPost's signature lineup of contributors

Dulio Denis Headshot

iOS Quick Read: Implementing a Custom UIActionSheet

Posted: Updated:
Print

This week the need arose to have a more powerful UIActionSheet that went beyond having just buttons. My initial reaction was to simply subclass UIActionSheet and add whatever was needed. But an argument arose at to whether this was the best approach since Apple clearly indicates in the UIActionSheet Class Reference that:

UIActionSheet is not designed to be subclassed, nor should you add views to its hierarchy. If you need to present a sheet with more customization than provided by the UIActionSheet API, you can create your own and present it modally with presentViewController:animated:completion:.

Although, I thought the above merely indicates the class is not designed to be subclassed, but it can the situation sparked my interest to create my own UIActionSheet template that I could reuse with the same animation types as Apple's. I'll describe step-by-step what I did to build the prototype and I have provided the sample project which is posted on GitHub that you can use as a reference to follow along step-by-step.

Step By Step:

1. I first created an iPhone Single View Application and in my Main.storyboard dragged a label to know this was my Main View. I then embedded the ViewController in a NavigationController so that I could have a Navigation bar.

Main Storyboard

2. In the MainViewController implementation I added a leftBarButton to viewDidLoad in order to popup a UIActionSheet and have something to compare to. I also made the MainViewController follow the UIActionSheetDelegate protocol.

self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemAction
target:self
action:@selector(showNonCustomView)];

3. I then added the UIActionSheet methods:

#pragma mark - show an Apple UIActionSheet

- (void)showNonCustomView {

UIActionSheet *popup = [[UIActionSheet alloc] initWithTitle:@"UIActionSheet"

delegate:self cancelButtonTitle:@"Cancel"

destructiveButtonTitle:nil

otherButtonTitles:@"Button to do an action", nil];

popup.tag = 1;

[popup showInView:[UIApplication sharedApplication].keyWindow];

}

- (void)actionSheet:(UIActionSheet *)popup clickedButtonAtIndex:(NSInteger)buttonIndex {

switch (popup.tag) {

case 1: {

switch (buttonIndex) {

case 0:

NSLog(@"Button to do an action");

break;

}

}

}

}

At this point this should give you an App that has a left bar button in the Navigation which pops up a standard UIActionSheet.

4. Then I created a new UIViewController subclass with XIB which I named DDAUIActionSheetViewController and put into its own Navigator Group in Xcode.

5. From the MainViewController implementation I went back to add a rightBarButton that calls the new Custom UIActionSheet. First add a property that is a pointer to the newly created custom class:

@property (nonatomic) DDAUIActionSheetViewController *customActionSheet;

6. Then in the MainViewController's viewDidLoad add:

self.customActionSheet = [[DDAUIActionSheetViewController alloc] init];

self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc]

initWithBarButtonSystemItem:UIBarButtonSystemItemAction

target:self

action:@selector(showCustomView)];

7. Then add the method to show the Custom Action Sheet as a result of the user selecting the right bar button:

#pragma mark - show the custom ActionSheet

- (void)showCustomView {

[self.navigationController.view addSubview:self.customActionSheet.view];

[self.customActionSheet viewWillAppear:NO];

}

8. In the viewWillAppear of the DDAUIActionSheetViewController implementation add a call to a slideIn method which will slide in the custom UIActionSheet. Then the slideIn method I added sets an initial location and animates a transition for the view in the ViewController.

- (void)slideIn {

//set initial location at bottom of view

CGRect frame = self.actionSheetView.frame;

frame.origin = CGPointMake(0.0, self.view.bounds.size.height);

self.actionSheetView.frame = frame;

[self.view addSubview:self.actionSheetView];

// set up an animation for the transition between the views

CATransition *animation = [CATransition animation];

[animation setDuration:0.5];

[animation setType:kCATransitionPush];

[animation setSubtype:kCATransitionFromTop];

[animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];

self.view.alpha=1.0f;

[[self.actionSheetView layer] addAnimation:animation forKey:@"TransitionToActionSheet"];

}

9. I then added a Tap Gesture Recognizer in the XIB for the View and in the implementation file I have the ViewController follow the UIGestureRecognizerDelegate and in viewWillAppear added:

UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self

action:@selector(handleTapFromView:)];

[self.view addGestureRecognizer:tapGestureRecognizer];

tapGestureRecognizer.delegate = self;

10. I then implement the handleTapFromView which will call a slide out method:

- (void) handleTapFromView: (UITapGestureRecognizer *)recognizer

{

[self slideOut];

}

11. Finally, the slide out method will have an animation to slide out the view and remove it from the superview:

- (void)slideOut {

[UIView beginAnimations:@"removeFromSuperviewWithAnimation" context:nil];

// Set delegate and selector to remove from superview when animation completes

[UIView setAnimationDelegate:self];

[UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)];

// Move this view to bottom of superview

CGRect frame = self.actionSheetView.frame;

frame.origin = CGPointMake(0.0, self.view.bounds.size.height);

self.actionSheetView.frame = frame;

[UIView commitAnimations];

}

- (void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context {

if ([animationID isEqualToString:@"removeFromSuperviewWithAnimation"]) {

[self.view removeFromSuperview];

}

}

That's it. Now you have an App that pops up the standard Apple UIActionSheet on the left bar button item and a right bar button item that pops up a custom UIActionSheet that you can expand on.

Custom Action Sheet

Where to next:
If you like what you've read and want to know more I suggest the WWDC 2012 Session Video by Matt Gamble & Bruce Nilo entitled Session 236: The Evolution of View Controllers and the Bruce Nilo follow-up WWDC 2013 Session Video entitled Session 218: Custom Transitions using View Controllers.

The first session discusses how best to take advantage of view controllers by examining what problems they were invented to address, how they've matured over the past releases, and how to be best prepared for where they're going next. The second session discusses how to take advantage of custom transitions by using powerful new animation APIs, explores changes with full screen layouts, and sees how to use navigation controllers with collection views to create truly immersive experiences.

Now go off and add your own custom Action Sheets in your killer app.