I was looking for a way to make a UIPickerView show a "Done", "Cancel" buttons.
Googling around I found good posts, all of them had UIActionSheet involved.
So I did that
container is a UIView
actionSheet is a UIActinSheet
pickerView is a UIPickerView
in viewDidLoad:
container = [[[UIView alloc] initWithFrame:CGRectMake(rect.origin.x,rect.origin.y, rect.size.width, rect.size.height)] autorelease];
[self.view addSubview:container];
actionSheet = [[UIActionSheet alloc] initWithTitle:#"myTitle"
delegate:nil
cancelButtonTitle:nil
destructiveButtonTitle:nil
otherButtonTitles:nil];
[actionSheet setActionSheetStyle:UIActionSheetStyleBlackTranslucent];
CGRect pickerFrame = CGRectMake(0, 40, 0, 0);
pickerView = [[[UIPickerView alloc] initWithFrame:pickerFrame]autorelease];
pickerView.showsSelectionIndicator = YES;
pickerView.dataSource = self;
pickerView.delegate = self;
UIToolbar *toolbar = [[[UIToolbar alloc] init] autorelease];
toolbar.frame = CGRectMake(0, 0, self.view.frame.size.width, 44);
NSMutableArray *items = [[[NSMutableArray alloc] init] autorelease];
[items addObject:[[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:#selector(dismissActionSheet)] autorelease]];
[items addObject:[[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:self action:#selector(goActionSheet)] autorelease]];
[items addObject:[[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:#selector(goActionSheet)] autorelease]];
[toolbar setItems:items animated:NO];
[actionSheet addSubview:toolbar];
[actionSheet addSubview:pickerView];
[actionSheet showInView:container];
[actionSheet setBounds:CGRectMake(0, 0, 320, 485)];
The app starts great, and the whole thing shows up nice as supposed to be on the line: [actionSheet showInView:container];
Now, When I try to dismiss the ActionSheet, it works great!
in dismissActionSheet:
[actionSheet dismissWithClickedButtonIndex:1 animated:NO];
The problem is, how do I make it show up again?
When I use:
[actionSheet showInView:container];
I only get the Toolbar picking from the bottom with the buttons and that's it. The whole PickerView is at the bottom and I can't see it.
What am I doing wrong here?
Action sheets are intended to be used more like alerts, in that they are standalone "make a choice now" presenters. They do normally only display part-way on the iPhone.
Your picker should be independent of the action sheet. If you want to have "Done" and "Cancel" buttons perhaps you would want to consider adding them to the picker's navigation bar?
You can use UIToolBar having Done and Cancel Button, with your PickerView, this will be easy.
Related
The navigation bar in my uinavigationbarcontroller is hidden, but my actionsheet thinks its still there, hence giving me a the highlights at the top of the action page (seen above). How can I erase this/ trick my actionsheet into thinking its a normal uiimageview?
Navigation bar hidden like so in didLoad:
[self.navigationController setNavigationBarHidden:YES animated:NO];
and:
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
if (![self.navigationController isNavigationBarHidden])
{
[self.navigationController setNavigationBarHidden:YES animated:animated];
}
}
actionsheet looks like this in didLoad:
actionSheet = [[UIActionSheet alloc] initWithTitle:#"" delegate:self cancelButtonTitle:nil destructiveButtonTitle:nil otherButtonTitles:nil];
UIToolbar *pickerToolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 200,320,16)];
[pickerToolbar sizeToFit];
pickerToolbar.barStyle = UIBarStyleBlackTranslucent;
NSMutableArray *barItems = [[NSMutableArray alloc] init];
UIBarButtonItem *cancelBtn = [[UIBarButtonItem alloc] initWithTitle:#"Cancel" style:UIBarButtonSystemItemCancel target:self action:#selector(cancel_clicked:)];
[barItems addObject:cancelBtn];
UIBarButtonItem *flexSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
[barItems addObject:flexSpace];
UIBarButtonItem *doneBtn = [[UIBarButtonItem alloc] initWithTitle:#"Done" style:UIBarButtonItemStyleDone target:self action:#selector(done_clicked:)];
[barItems addObject:doneBtn];
[pickerToolbar setItems:barItems animated:YES];
[actionSheet addSubview:pickerToolbar];
UIPickerView *locationPicker = [[UIPickerView alloc] init];
locationPicker.frame = CGRectMake(0, 244, 320, 216);
locationPicker.delegate = self;
locationPicker.dataSource = self;
locationPicker.showsSelectionIndicator = YES;
locationPicker.tag = 1;
[actionSheet addSubview:locationPicker];
Then its animated in on textfield touch.
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
if (textField == locationTextField.self)
{
[actionSheet showInView:self.view];
[actionSheet setFrame:CGRectMake(0, 0, 320, 480)];
[nameField resignFirstResponder];
}
}
I believe the problem is with the view you chose to show the action sheet. try to show it in your app's main window.
Hi Can anyone help me out with this, ive been looking at alot of the previous questions on this subject and they seem a little complicated. I want to setup a picker that animates in on the touch of a text field which has an IBOutlet called locationField.
I dont want to add the picker or toolbar and buttons in my story boards I would rather do it programatically.
So far I have:
- (void)viewDidLoad
{
//populate picker arrays
locationPickerArray = [[NSArray alloc] initWithObjects:#"1",#"2",#"3",#"4",#"5", nil];
actionSheet = [[UIActionSheet alloc] initWithTitle:#"" delegate:self cancelButtonTitle:nil destructiveButtonTitle:nil otherButtonTitles:nil];
[actionSheet showInView:self.view];
UIToolbar *pickerToolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0,480,32)];
[pickerToolbar sizeToFit];
pickerToolbar.barStyle = UIBarStyleBlackTranslucent;
NSMutableArray *barItems = [[NSMutableArray alloc] init];
UIBarButtonItem *cancelBtn = [[UIBarButtonItem alloc] initWithTitle:#"Cancel" style:UIBarButtonSystemItemCancel target:self action:#selector(cancel_clicked:)];
[barItems addObject:cancelBtn];
UIBarButtonItem *flexSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
[barItems addObject:flexSpace];
UIBarButtonItem *doneBtn = [[UIBarButtonItem alloc] initWithTitle:#"Done" style:UIBarButtonItemStyleDone target:self action:#selector(done_clicked:)];
[barItems addObject:doneBtn];
[pickerToolbar setItems:barItems animated:YES];
[actionSheet addSubview:pickerToolbar];
UIPickerView *picker = [[UIPickerView alloc] init];
picker.frame = CGRectMake(0, 44, 320, 216);
picker.delegate = self;
picker.dataSource = self;
picker.showsSelectionIndicator = YES;
[actionSheet addSubview:picker];
}
-(void)done_clicked:(id)sender
{
[actionSheet dismissWithClickedButtonIndex:0 animated:YES];
}
-(void)cancel_clicked:(id)sender
{
[actionSheet dismissWithClickedButtonIndex:0 animated:YES];
}
I have a few questions about this, it crashes on:
* Terminating app due to uncaught exception
'NSInvalidArgumentException', reason: '-[DetailsScreenViewController
numberOfComponentsInPickerView:]: unrecognized selector sent to
instance 0xb505be0'
What does this mean?
My final question is how can I populate this picker and assign it to popup when the iboutlet I created earlier is clicked (location field).
Thank you
The reason for your crash is that you've assigned an instance of DetailsScreenViewController to be the dataSource and delegate of a UIPickerView without actually implementing the methods for these protocols. The assignment takes place here:
picker.delegate = self;
picker.dataSource = self;
The specific crash is telling you that you haven't implemented numberOfComponentsInPickerView:, part of the UIPickerViewDataSource protocol. You should have gotten a compiler warning about this actually. Learning to use those warnings can be really helpful! Anyways, to fix it, provide implementations for all of the required methods on both protocols. The details of the implementations will depend on the needs for your app. If you still need help with details let me know.
Regarding your second question, I guess putting a UIPickerView inside a UIActionSheet is a thing now. I've never had a need to do it before, but here is a SO question with a lot of sample code for some background, not sure if you've read that one yet. But I think you'd just want to wait for the time you actually want to show the picker to call
[actionSheet showInView:self.view];
I think you can do this in a UITextFieldDelegate method, there are probably other ways. I'm going to try to do some experiments with that later and update this post.
EDIT:
If you assign your view controller as the delegate of whatever text field you're interested in, then you can implement this UITextFieldDelegate method:
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
[actionSheet showInView:self.view];
return NO;
}
END EDIT
Hope this helps, and let me know if you have any questions.
I have read on another post (how to dismiss action sheet) that I can use
[actionSheet dismissWithClickedButtonIndex:0 animated:YES];
to dismiss the uiactionsheet with the close button, as defined in:
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:nil
delegate:nil
cancelButtonTitle:nil
destructiveButtonTitle:nil
otherButtonTitles:nil];
[actionSheet setActionSheetStyle:UIActionSheetStyleBlackTranslucent];
CGRect pickerFrame = CGRectMake(0, 40, 0, 0);
UIPickerView *pickerView = [[UIPickerView alloc] initWithFrame:pickerFrame];
pickerView.showsSelectionIndicator = YES;
pickerView.dataSource = self;
pickerView.delegate = self;
[actionSheet addSubview:pickerView];
[pickerView release];
UISegmentedControl *closeButton = [[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObject:#"Close"]];
closeButton.momentary = YES;
closeButton.frame = CGRectMake(260, 7.0f, 50.0f, 30.0f);
closeButton.segmentedControlStyle = UISegmentedControlStyleBar;
closeButton.tintColor = [UIColor blackColor];
[closeButton addTarget:self action:#selector(dismissActionSheet:) forControlEvents:UIControlEventValueChanged];
[actionSheet addSubview:closeButton];
[actionSheet dismissWithClickedButtonIndex:0 animated:YES];
[closeButton release];
[actionSheet showInView:[[UIApplication sharedApplication] keyWindow]];
[actionSheet setBounds:CGRectMake(0, 0, 320, 485)];
However, I am not sure where to place this line, assuming this will solve my problem:
[actionSheet dismissWithClickedButtonIndex:0 animated:YES];
Also, the app crashes when I click the close button, with error message "PROGRAM RECEIVED ERROR MESSAGE SIGBRT". I assume my two problems are related. Any help out there?
Just implement dismissActionSheet and put your dismiss message there.
The dismissActionSheet method would look something like this:
-(void)dismissActionSheet {
[sheet dismissWithClickedButtonIndex:0 animated:YES];
}
I am trying to display a UIActionSheet on the iPad with a UIPickerView in it, I have the equivalent code working for iPhone so my UIPickerView delegate and datasource stuff work, but on the iPad when I use -[UIActionSheet showFromRect:inView:animated:] the result UIPopover/UIActionSheet is way too small and I can not seem to set the frame size, also none of the buttons are displayed.
I don't know if this is because they are outside the bounds or there is something else going on. This is what my code looks like after I have removed all non-essential code (iPhone etc). Does anybody know what I am doing wrong, does anybody know of any examples.
CGRect thePickerFrame = CGRectMake(0, 0, 320.0, 485.0);
UIPickerView * thePickerView = [[UIPickerView alloc] initWithFrame:thePickerFrame];
[pickerActionSheet release], pickerActionSheet =
[[UIActionSheet alloc] initWithTitle:#"Choose" delegate:self
cancelButtonTitle:#"Cancel"
destructiveButtonTitle:nil
otherButtonTitles:#"Next", nil];
thePickerView.showsSelectionIndicator = YES;
thePickerView.dataSource = self;
thePickerView.delegate = self;
[pickerActionSheet addSubview:thePickerView];
[thePickerView selectRow:0 inComponent:0 animated:NO];
[thePickerView release];
[pickerActionSheet showFromRect:currentTextField.bounds
inView:currentTextField animated:NO];
pickerActionSheet.frame = thePickerFrame;
I think that UIActionSheet is not resizable, try to comment in your code the line with [pickerActionSheet addSubview:thePickerView]; and you will see that the ActionSheet fits perfecly to the buttons.
I would recommend a UIPopoverController with a custom UIViewController. Something like this:
UIToolbar *toolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];
toolbar.barStyle = UIBarStyleDefault;
UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc] initWithTitle:#"back" style:UIBarButtonItemStyleBordered target:self action:#selector(BACK_ACTION:)];
UIBarButtonItem *chooseButton = [[UIBarButtonItem alloc] initWithTitle:#"Choose" style:UIBarButtonItemStylePlain target:nil action:nil];
UIBarButtonItem *nextButton = [[UIBarButtonItem alloc] initWithTitle:#"Next" style:UIBarButtonItemStyleBordered target:self action:#selector(NEXT_ACTION:)];
UIBarButtonItem *fixed1 = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
UIBarButtonItem *fixed2 = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
[toolbar setItems:[NSArray arrayWithObjects:cancelButton, fixed1, chooseButton, fixed2, nextButton, nil]];
UIPickerView *thePickerView = [[UIPickerView alloc] initWithFrame:CGRectMake(0, 44, 320, 216)];
CGRect thePickerFrame = thePickerView.frame;
thePickerFrame.origin.y = toolbar.frame.size.height;
[thePickerView setFrame:thePickerFrame];
UIView *view = [[UIView alloc] init];
[view addSubview:thePickerView];
[view addSubview:toolbar];
UIViewController *vc = [[UIViewController alloc] init];
[vc setView:view];
[vc setContentSizeForViewInPopover:CGSizeMake(320, 260)];
popover = [[UIPopoverController alloc] initWithContentViewController:vc];
thePickerView.showsSelectionIndicator = YES;
thePickerView.dataSource = self;
thePickerView.delegate = self;
[thePickerView selectRow:0 inComponent:0 animated:NO];
[popover presentPopoverFromRect:currentTextField.bounds inView:currentTextField permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
Where popover is a class variable declared in .h (UIPopoverController *popover;).
By the way, I'm using ARC, so there is no release in the code.
I managed to make it work using a silly way.
For your reference:
Setup PickerView.
UIActionSheet's width can't be adjusted somehow, so have to adjust pickerView accordingly. Height wise, you can adjust with the amount of "\n" in actionSheet title.
UIDatePicker * pickerView = [[UIDatePicker alloc] initWithFrame:CGRectMake(0, 0, 270, 220)];
pickerView.datePickerMode = UIDatePickerModeDate;
UIActionSheet * actionSheet = [[UIActionSheet alloc] initWithTitle:#"\n\n\n\n\n\n\n\n\n\n\n\n\n" delegate:nil cancelButtonTitle:nil destructiveButtonTitle:nil otherButtonTitles: nil];
[actionSheet setActionSheetStyle:UIActionSheetStyleBlackTranslucent];
[actionSheet addSubview:pickerView];
[actionSheet showFromRect:button.frame inView:button.superview animated:YES];
[actionSheet release];
Set Frame or Bound doesn't work for me.
[actionSheet setBounds:pickerView.frame];
[actionSheet setFrame:pickerView.frame];
Agreed on using UIPopoverController, but don't know why, it got a serious UI delay when I put UIDatePickerView into popover (it took almost 1 sec lag to pop up) which I can't find the root cause. So have to fallback to above method.
Happy Coding.
I'm trying to get a UIDatePicker with a UIButton to show up in a UIActionSheet. Unfortunately it gets cropped off and the entire Date Picker is not visible. I have not even attempted to add the UIButton yet. Can anyone suggest on getting the entire view to fit properly? I'm not sure how to add the proper dimensions as UIActionSheet seems to lack an -initWithFrame: type constructor.
UIActionSheet *menu = [[UIActionSheet alloc] initWithTitle:#"Date Picker"
delegate:self
cancelButtonTitle:#"Cancel"
destructiveButtonTitle:nil
otherButtonTitles:nil];
// Add the picker
UIDatePicker *pickerView = [[UIDatePicker alloc] init];
pickerView.datePickerMode = UIDatePickerModeDate;
[menu addSubview:pickerView];
[menu showInView:self.view];
[pickerView release];
[menu release];
I've also tried with something similar to:
UIActionSheet *menu = [[UIActionSheet alloc] initWithFrame:CGRectMake(200.0, 200.0, 100.0f, 100.0f)];
The coords are ofcourse not realistic, but they don't seem to affect the position/size of the UIActionSheet.
You can use something like this (adjust the coordinates):
UIActionSheet *menu = [[UIActionSheet alloc] initWithTitle:#"Date Picker"
delegate:self
cancelButtonTitle:#"Cancel"
destructiveButtonTitle:nil
otherButtonTitles:nil];
// Add the picker
UIDatePicker *pickerView = [[UIDatePicker alloc] init];
pickerView.datePickerMode = UIDatePickerModeDate;
[menu addSubview:pickerView];
[menu showInView:self.view];
[menu setBounds:CGRectMake(0,0,320, 500)];
CGRect pickerRect = pickerView.bounds;
pickerRect.origin.y = -100;
pickerView.bounds = pickerRect;
[pickerView release];
[menu release];
But you better create a fullscreen view with a UIDatePicker and a navigation bar. For an example see UICatalog -> Pickers sample from the iPhone DevCenter.
Try adding following line to resolve disabled buttons issue
[menu sendSubviewToBack:pickerView];
Dmitry's answer is almost correct. However, the frame of the actionsheet is too small, and therefore touches near the bottom of the picker are ignored. I have corrected these problems:
UIActionSheet *menu = [[UIActionSheet alloc] initWithTitle:#"Date Picker"
delegate:self
cancelButtonTitle:#"Cancel"
destructiveButtonTitle:nil
otherButtonTitles:#"OK",nil];
// Add the picker
UIDatePicker *pickerView = [[UIDatePicker alloc] init];
pickerView.datePickerMode = UIDatePickerModeTime;
[menu addSubview:pickerView];
[menu showInView:_mainView];
CGRect menuRect = menu.frame;
CGFloat orgHeight = menuRect.size.height;
menuRect.origin.y -= 214; //height of picker
menuRect.size.height = orgHeight+214;
menu.frame = menuRect;
CGRect pickerRect = pickerView.frame;
pickerRect.origin.y = orgHeight;
pickerView.frame = pickerRect;
[pickerView release];
[menu release];
This works for me
NSString *title = UIDeviceOrientationIsLandscape([UIDevice currentDevice].orientation) ? #"\n\n\n\n\n\n\n\n\n" : #"\n\n\n\n\n\n\n\n\n\n\n\n" ;
UIActionSheet *actionSheet = [[UIActionSheet alloc]
initWithTitle:[NSString stringWithFormat:#"%#%#", title, NSLocalizedString(#"SelectADateKey", #"")]
delegate:self cancelButtonTitle:nil destructiveButtonTitle:nil otherButtonTitles:#"Ok", nil];
[actionSheet showInView:self.view];
UIDatePicker *datePicker = [[[UIDatePicker alloc] init] autorelease];
datePicker.datePickerMode = UIDatePickerModeDate;
[actionSheet addSubview:datePicker];
a little tricky but it works!
Buttons at top, picker at bottom:
UIActionSheet *menu = [[UIActionSheet alloc] initWithTitle:#"Date Picker"
delegate:self
cancelButtonTitle:#"Cancel"
destructiveButtonTitle:nil
otherButtonTitles:#"OK",nil];
// Add the picker
UIDatePicker *pickerView = [[UIDatePicker alloc] init];
pickerView.datePickerMode = UIDatePickerModeTime;
[menu addSubview:pickerView];
[menu showInView:_mainView];
CGRect menuRect = menu.frame;
menuRect.origin.y -= 214;
menuRect.size.height = 300;
menu.frame = menuRect;
CGRect pickerRect = pickerView.frame;
pickerRect.origin.y = 174;
pickerView.frame = pickerRect;
[pickerView release];
[menu release];
Make sure you show the UIActionSheet in the right view when inside a UITabBarController to avoid interactivity problems at the bottom:
[actionSheet showInView:self.parentViewController.tabBarController.view];
Possibly not directly answering the specific question (how to get the UIDatePicker to fit), but for an implementation of UIActionSheet which presents a UIDatePicker (also others) please see ActionSheetPicker. From it's Readme:
Easily present an ActionSheet with a PickerView, allowing user to select from a number of immutable options. Based on the HTML drop-down alternative found in mobilesafari.
Also:
Some code derived from marcio's post on Stack Overflow
[ Add UIPickerView & a Button in Action sheet - How? ]
Even if one doesn't use the code, it's good reading before you roll your own.
Update:
This version is deprecated: use ActionSheetPicker-3.0 instead.