Fitting a UIDatePicker into a UIActionSheet - objective-c

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.

Related

set font size to UIActionSheet title

I need to set size UIActionSheet title "Select option to Copy"
with this code :
[[UIActionSheet alloc] initWithTitle:#"Select option to copy:" delegate:self cancelButtonTitle:#"Cancel" destructiveButtonTitle:nil
otherButtonTitles:#"copy all ",nil];
You could take advantage of Runtime Properties to set the font. By using NSAttributedString you can achieve this.
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:#"" delegate:self cancelButtonTitle:#"Cancel" destructiveButtonTitle:nil
otherButtonTitles:#"copy all ",nil];
//Creating Attributed String with System Font size of 30.0f
NSAttributedString *attrString = [[NSAttributedString alloc] initWithString:#"Select option to copy:" attributes:#{NSFontAttributeName: [UIFont systemFontOfSize:30.0f]}];
//Accessing the Alert View Controller property from Action Sheet
UIAlertController *alertController = [actionSheet valueForKey:#"_alertController"];
//Setting Attributed Title property of Alert View Controller
[alertController setValue:attrString forKey:#"_attributedTitle"];
//Displaying the Action Sheet
[actionSheet showInView:self.view];
You can change the title font of uiactionsheet by using this delgate
-(void)willPresentActionSheet:(UIActionSheet *)actionSheet {
for (UIView *_currentView in actionSheet.subviews) {
if ([_currentView isKindOfClass:[UILabel class]]) {
UILabel *l = [[UILabel alloc] initWithFrame:_currentView.frame];
l.text = [(UILabel *)_currentView text];
[l setFont:[UIFont fontWithName:#"Arial-BoldMT" size:20]];
l.textColor = [UIColor darkGrayColor];
l.backgroundColor = [UIColor clearColor];
[l sizeToFit];
[l setCenter:CGPointMake(actionSheet.center.x, 25)];
[l setFrame:CGRectIntegral(l.frame)];
[actionSheet addSubview:l];
_currentView.hidden = YES;
break;
}
}
}

textField does not show in the alertView

Here is my code:
UIAlertView *theAlert = [[UIAlertView alloc] initWithTitle:#"Alert" message:nil delegate:self cancelButtonTitle:nil otherButtonTitles:#"OK", nil];
UITextField *textField = [[UITextField alloc] initWithFrame: CGRectMake(12, 45, 260, 30)];
[textField setBackgroundColor: [UIColor clearColor]];
textField.borderStyle = UITextBorderStyleRoundedRect;
[theAlert addSubview:textField];
[theAlert show];
[textField release];
[theAlert release];
There is no textFiled in alertView, only a title "Alert" and a button "OK"
I will refer you the Apple Documentation in regards to UIAlertView Class Reference. Specifically
Subclassing Notes
The UIAlertView class is intended to be used as-is and does not support subclassing. The view hierarchy for this class is private and must not be modified
So what this means is you can't add subviews to an instance of UIAlertView the recent UIAlertView still has the addSubview: method is because UIAlertView is a subclass of UIView which has this method, but as of iOS7 the method addSubview: for UIAlertView no longer calls the super method on UIView it just does nothing.
So basically what you are after is not possible.
There are however alertViewStyles that you can use like UIAlertViewStylePlainTextInput which will add a single UITextField to the UIAlertView which you can then access using the method textFieldAtIndex:. However please be aware that you can't really do anything with this again because it is part of the UIAlertViews hierarchy so again it is made to be used as is.
Messing with the UIAlertView hierarchy will get your app rejected from the Apple Review process under
2.5 - Apps that use non-public APIs will be rejected
your background color is clear so It's not showing
[textField setBackgroundColor: [UIColor redColor]];.
and also show default text field
theAlert.alertViewStyle = UIAlertViewStylePlainTextInput;
//or for username and password
theAlert.alertViewStyle = UIAlertViewStyleLoginAndPasswordInput;
// or for password
theAlert.alertViewStyle = UIAlertViewStyleSecureTextInput;
Try this
You can use the default alertView with textfield.For that you need to set the alertViewStyle
[message setAlertViewStyle:UIAlertViewStylePlainTextInput];
Here message is object of alertView.
You can get the textfield value using the delegate method as shown below
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
NSString *title = [alertView buttonTitleAtIndex:buttonIndex];
if([title isEqualToString:#"Login"]) {
UITextField *username = [alertView textFieldAtIndex:0];
UITextField *password = [alertView textFieldAtIndex:1];
NSLog(#"Username: %#\nPassword: %#", username.text, password.text);
}
}
Or you can set alert.alertViewStyle = UIAlertViewStylePlainTextInput;
This will add a text field for you. You can access it in the
UIAlertView delegate callback by using
UITextField *textField = [alertView textFieldAtIndex:0];
If your using ios 7 then add below code to your set of code
theAlert.alertViewStyle=UIAlertViewStylePlainTextInput;
Full code
UIAlertView *theAlert = [[UIAlertView alloc] initWithTitle:#"Alert" message:nil delegate:self cancelButtonTitle:nil otherButtonTitles:#"OK", nil];
UITextField *textField = [[UITextField alloc] initWithFrame: CGRectMake(12, 45, 260, 30)];
[textField setBackgroundColor: [UIColor greenColor]];
textField.borderStyle = UITextBorderStyleRoundedRect;
theAlert.alertViewStyle=UIAlertViewStylePlainTextInput;
[theAlert show];

UIActionSheet comes up halfway

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.

selector for a UIDatePicker with args (UITextfiled)

I've seen a lot of text fields with triggering a datepicker.
I want have only one method to make a datepicker. This datepicker must have a method selector with the identifier of the text fields. I don't know how can i make this.
Here is my code:
- (IBAction)launchPickerDate:(id)sender{
UIDatePicker *datepickerNew = [UIDatePicker new];
[datepickerNew setHidden:NO];
datepickerNew.frame = CGRectOffset(datepickerNew.frame, 0, 244);
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:nil
delegate:nil
cancelButtonTitle:nil
destructiveButtonTitle:nil
otherButtonTitles:nil];
[actionSheet setActionSheetStyle:UIActionSheetStyleBlackTranslucent];
CGRect pickerFrame = CGRectMake(0, 40, 0, 0);
UIDatePicker *launchPickerDate = [[UIDatePicker alloc] initWithFrame:pickerFrame];
[launchPickerDate addTarget:self action:#selector(SelectDatePicker:) forControlEvents:UIControlEventValueChanged];
[actionSheet addSubview:launchPickerDate];
UISegmentedControl *closeButton = [[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObject:#"Ok"]];
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(closeDatePicker:) forControlEvents:UIControlEventValueChanged];
[actionSheet addSubview:closeButton];
[actionSheet showInView:[[UIApplication sharedApplication] keyWindow]];
[actionSheet setBounds:CGRectMake(0, 0, 320, 485)];
}
I didn't really get your question but it seems to me you want to make some changes to your date picker based upon the text field selected. You can recognize the textfield from which the method was called using the tag property. Like
if (sender.tag==1){
//do something as first text field selected
}else if(sender.tag==2){
//do something as second text field selected
}
you can specify the tags for text field either by interface builder(if you are using xib's) or via code like. firstTextField.tag=1;
and so on.. hope this helps... if anything else just let me know

UIActionSheet on iPad frame too small

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.