[Tutorial] How to add Pickers to an actionsheet

Discussion in 'iOS Development' started by flyingguitar, Jul 26, 2010.

  1. flyingguitar

    flyingguitar Active Member

    Joined:
    May 14, 2008
    Messages:
    1,870
    Likes Received:
    11
    Device:
    iPhone 4 (Black)
    This can also be applied to pretty much and other view, but this is a pretty basic example. We're going to show an action sheet with a date picker in it. Then based on the date that was selected, We will show an alert displaying that date. So let's start with this.

    [OBJC]-(IBAction) buttonPressed {
    UIActionSheet *asheet = [[UIActionSheet alloc] initWithTitle:mad:"Pick the date you want to see." delegate:self cancelButtonTitle:mad:"Cancel" destructiveButtonTitle:nil otherButtonTitles:mad:"Select", nil];
    [asheet showInView:[self.view superview]]; //note: in most cases this would be just self.view, but because I was doing this in a tabBar Application, I use the superview.
    [asheet setFrame:CGRectMake(0, 117, 320, 383)];
    [asheet release];
    }
    [/OBJC]

    When a user clicks the button that triggers this code, we will make an action sheet. The only thing that's different here than making a regular action sheet, is the line

    [OBJC][asheet setFrame:CGRectMake(0, 117, 320, 383)];[/OBJC]

    this makes the action sheet's frame big enough to hold our picker as well as some buttons. You might have to play with the numbers a bit to make it the correct size. However, (assuming the action sheet is in portrait mode) the first argument should always be 0, the third argument should always be 320, and the second and fourth argument should always add up to 480. The Last argument being the size for the action sheet, and the second saying how far down the screen until the action sheet is displayed.

    Now we are going to play with the view a little bit in the willPresentActionSheet: method, this is where we will configure all of the subviews.

    [OBJC]
    #define kDatePickerTag 100

    - (void)willPresentActionSheet:(UIActionSheet *)actionSheet {

    UIDatePicker *pickerView = [[UIDatePicker alloc] initWithFrame:CGRectMake(0, 40, 320, 216)];

    //Configure picker...
    [pickerView setMinuteInterval:5];
    [pickerView setTag: kDatePickerTag];

    //Add picker to action sheet
    [actionSheet addSubview:pickerView];

    [pickerView release];

    //Gets an array af all of the subviews of our actionSheet
    NSArray *subviews = [actionSheet subviews];

    [[subviews objectAtIndex:SelectButtonIndex] setFrame:CGRectMake(20, 266, 280, 46)];
    [[subviews objectAtIndex:CancelButtonIndex] setFrame:CGRectMake(20, 317, 280, 46)];


    }[/OBJC]

    I think it's worth mentioning that I have SelectButtonIndex defined to the constant 1, as well as CancelButtonIndex defined to the constant 2. So this is pretty straightforward, we allocate an instance of UIDatePicker, then configure it. Make sure to set the frame to the correct value based on your action sheet. However the height of the picker is always going to be 216 in portrait, and the title label is 40 pixels tall. once we have the Picker added, you'll notice that it covers up the buttons. To fix this we grab an array of subviews from the action sheet and stick the buttons under the picker so that we can see and click them ;D

    Now unfortunately pickers aren't very useful unless you can retrieve a value from them. I'll show you how to do that in the actionSheet:clickedButtonAtIndex: method.

    [OBJC]- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
    if (buttonIndex != [actionSheet cancelButtonIndex]) {

    //set Date formatter
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    [formatter setDateFormat:mad:"MM/dd/YYYY h:mm a"];

    //Gets our picker
    UIDatePicker *ourDatePicker = (UIDatePicker *) [actionSheet viewWithTag:kDatePickerTag];

    NSDate *selectedDate = [ourDatePicker date];

    NSString *msg = [[NSString alloc] initWithFormat:mad:"The date that you had selected was, %@", [formatter stringFromDate:selectedDate]];
    [formatter release];

    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:mad:"Date" message:msg delegate:nil cancelButtonTitle:mad:"Dismiss" otherButtonTitles:nil];
    [alert show];
    [alert release];
    [msg release];
    }
    }
    [/OBJC]

    So this is all pretty simple too. First we create a date formatter so that our date can look nice and presentable for our users ;). Next we grab a reference to the picker based on the tag we set earlier. once we have a reference to our picker we create a string using the formatter and use that string to create an alert.

    As stated in the beginning of the tutorial, this technique can be applied to most other views as well. the basic idea is the same. So you can have fun with it :D

    EDIT: If you know how to do this using by making a subclass of UIActionSheet. I would highly recommend doing it that way. Otherwise, just stick to the approach done here.

    screenies:

    [​IMG]

    [​IMG]

    Yes I know you like my sexy orange background XD

    Attached Files:

  2. SkylarEC

    SkylarEC Super Moderator Emeritus Staff Member

    Joined:
    Sep 19, 2007
    Messages:
    6,652
    Likes Received:
    122
    As you mentioned, the far better way is to simply subclass the UIAlertSheet. That itself is a very simple process and is well worth the time to set up.

    Reusable classes and objects are things that devs should strive for.
  3. Steaps

    Steaps New Member

    Joined:
    Oct 24, 2007
    Messages:
    5,075
    Likes Received:
    40
    Device:
    iPod touch
    You should try playing around with the images of UIDatePicker (Through subviews, etc.) in a subclass, and try to have the border around the UIDatePicker 'fit' in with the UIActionSheet. Would look much, much better! Always fun customizing things.

    Please don't try to tell me it's impossible.
  4. flyingguitar

    flyingguitar Active Member

    Joined:
    May 14, 2008
    Messages:
    1,870
    Likes Received:
    11
    Device:
    iPhone 4 (Black)
    I agree it would look much better. Although it's very hard to change the boarder of a picker using only documented methods. it's probably easier to change the rest of the view to accommodate the picker rather than the other way around.
  5. SkylarEC

    SkylarEC Super Moderator Emeritus Staff Member

    Joined:
    Sep 19, 2007
    Messages:
    6,652
    Likes Received:
    122
    No it's not. Just output the list of classes and change the neccessary subviews. To get the array of subviews the picker contains.
  6. flyingguitar

    flyingguitar Active Member

    Joined:
    May 14, 2008
    Messages:
    1,870
    Likes Received:
    11
    Device:
    iPhone 4 (Black)
    hmm. I'll look into that
  7. Unregistered

    Unregistered Guest

    Exception

    Hello,

    i have a tabBar app too, i tried to put the code as it is the 3 methods in order and i have tihs exception at runtime :

    Code:
    2010-12-02 14:05:53.935 TALAN[12827:207] *** Assertion failure in -[UIActionSheet showInView:], /SourceCache/UIKit_Sim/UIKit-1261.5/UIActionSheet.m:4034
    2010-12-02 14:05:53.937 TALAN[12827:207] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid parameter not satisfying: view != nil'
    *** Call stack at first throw:
    (
    	0   CoreFoundation                      0x02590919 __exceptionPreprocess + 185
    	1   libobjc.A.dylib                     0x026de5de objc_exception_throw + 47
    	2   CoreFoundation                      0x02549078 +[NSException raise:format:arguments:] + 136
    	3   Foundation                          0x000c88cf -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 116
    	4   UIKit                               0x00757f1a -[UIActionSheet showInView:] + 155
    	5   TALAN                               0x0000496e -[TALANViewController viewDidLoad] + 193
    	6   UIKit                               0x004be924 -[UINib instantiateWithOwner:options:] + 1556
    	7   UIKit                               0x004c04b5 -[NSBundle(UINSBundleAdditions) loadNibNamed:owner:options:] + 168
    	8   UIKit                               0x002cf9bb -[UIApplication _loadMainNibFile] + 172
    	9   UIKit                               0x002d090d -[UIApplication _runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:] + 198
    	10  UIKit                               0x002da452 -[UIApplication handleEvent:withNewEvent:] + 1958
    	11  UIKit                               0x002d3074 -[UIApplication sendEvent:] + 71
    	12  UIKit                               0x002d7ac4 _UIApplicationHandleEvent + 7495
    	13  GraphicsServices                    0x02df6afa PurpleEventCallback + 1578
    	14  CoreFoundation                      0x02571dc4 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 52
    	15  CoreFoundation                      0x024d2737 __CFRunLoopDoSource1 + 215
    	16  CoreFoundation                      0x024cf9c3 __CFRunLoopRun + 979
    	17  CoreFoundation                      0x024cf280 CFRunLoopRunSpecific + 208
    	18  CoreFoundation                      0x024cf1a1 CFRunLoopRunInMode + 97
    	19  UIKit                               0x002d0226 -[UIApplication _run] + 625
    	20  UIKit                               0x002dbb58 UIApplicationMain + 1160
    	21  TALAN                               0x000027fc main + 102
    	22  TALAN                               0x0000278d start + 53
    )
    terminate called after throwing an instance of 'NSException'
    can you help me to find the error

    Thank you
  8. NolesFans

    NolesFans New Member

    Joined:
    Sep 23, 2008
    Messages:
    406
    Likes Received:
    0
    Device:
    iPod touch
    It is "Invalid parameter not satisfying: view != nil"
  9. flyingguitar

    flyingguitar Active Member

    Joined:
    May 14, 2008
    Messages:
    1,870
    Likes Received:
    11
    Device:
    iPhone 4 (Black)
    what view are you trying to show it in?
  10. Unregistered

    Unregistered Guest

    Picker on action sheet

    Thanks so much for putting this up! It is really helpful to me

Share This Page