Hiding/ Showing UIPickerView
I Have an a touchesEnded event that checks for when a UITextField is pressed. What I would like it to do is is hide/show a UIPickerView. How can this be done?
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [[event allTouches] anyObject];
if (CGRectContainsPoint([self.textField frame], [touch locationInView:self.view]))
{
NSString * error = @"Touched the TextField";
UIAlertView * errorAlert = [[UIAlertView alloc] initWithTitle:@"Selection!" message:error delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
[errorAlert show];
//Want to show or hide UIPickerView
}
}
I already have an allocated UIPickerView when touches occur
@interface ThirdViewController : UIViewController <UITe开发者_StackOverflow中文版xtFieldDelegate,UIPickerViewDelegate> {
IBOutlet UIPickerView *pickerView;
}
Toggling the "hidden" property will do the trick, but will also give a very abrupt reveal.
One way to avoid this is to get the picker to slide up from the bottom of the screen by embedding it inside a UIActionSheet.
Here's an example:
UIActionSheet *sheet = [[UIActionSheet alloc] initWithTitle:nil
delegate:nil cancelButtonTitle:nil destructiveButtonTitle:nil otherButtonTitles:nil];
CGRect pickerFrame = CGRectMake(0, 0, 0, 0);
UIPickerView *pickerView = [[UIPickerView alloc] initWithFrame:pickerFrame];
pickerView.showsSelectionIndicator = YES;
pickerView.dataSource = self;
pickerView.delegate = self;
[sheet addSubview:pickerView];
[pickerView release];
[sheet showInView:view];
[sheet setBounds:CGRectMake(0, 0, 320, 415)];
self.actionSheet = sheet; // assuming you have setup a property to hold the action sheet
[sheet release];
When you've finished with the picker, dismiss it:
[self.actionSheet dismissWithClickedButtonIndex:0 animated:YES];
This approach can also be used to incorporate buttons in a bar above the picker ("Done", "Previous", "Next" etc) - there's a good explanation of how to do it here.
Because I saw a comment about these solutions not working on iOS 7 I will assume this thread is still relevant and being searched for.
The best way I have found to do this is by attaching the UIPickerView to a (hidden)UITextField as the input view like:
_myPicker = [[UIPickerView alloc] init];
_myPicker.delegate = self;
_myPicker.showsSelectionIndicator = YES;
myTextField.inputView = _myPicker;
You can always hide the text field if desired. Then you can show/hide the UIPickerView by activating the textfield as first responder like:
[myTextField becomeFirstResponder];
[myTextField resignFirstResponder];
I have verified this works on iOS 7 and I have had it working as far back as iOS 5.
UIPickerView inherits from UIView, so you should be able to just toggle its 'hidden' property:
if (pickerView) pickerView.hidden = !pickerView.hidden;
I am using a dummy UITextField
for showing / hiding the UIPickerView
First, add a UITextField as a @property
on your UIViewController
. Optionally, add the UIPickerView
, as well
@property (strong, nonatomic) UITextField *dummyTextField;
Second, assign a UIPickerView
as inputView
for the UITextField
. Assign yourself as the dataSource
and the delegate
for the UIPickerView
. UITextField
needs to be added as a subview on your UIViewController
's view
.
- (void)viewDidLoad {
[super viewDidLoad];
UIPickerView *picker = [[UIPickerView alloc] init];
[picker setDataSource:self];
[picker setDelegate:self];
self.dummyTextField = [UITextField new];
self.dummyTextField.inputView = picker;
[self.dummyTextField setHidden:YES];
[self.view addSubview:self.dummyTextField];
}
Finally, add a mechanism to show and hide the UIPickerView
. Since I am using a dummy UITextField
, I have decided to add a UIBarButtonItem
named "Filter" with the following IBAction
:
- (IBAction)tappedFilterButton:(UIBarButtonItem *)sender {
if (self.dummyTextField.isFirstResponder) {
[self.dummyTextField resignFirstResponder];
}
else {
[self.dummyTextField becomeFirstResponder];
}
}
So I have used many references on trying to figure this out and then my best reference (believe it or not), was from the apple docs on UIView Class reference.
I built a mini View ("_pickerView" on top of my main view that held a UIToolBar, UIToolButton (With IBAction "closePicker"), and the UIPicker.
***please note that is only works for iOS 4.0 and up
the code for closing and displaying the UIView ("_pickerView") is:
-(IBAction)closePicker:(id)sender
{
[UIView animateWithDuration:0.3 animations:^{
_pickerView.frame = CGRectMake(_pickerView.frame.origin.x,
460, //Displays the view off the screen
_pickerView.frame.size.width,
_pickerView.frame.size.height);
}];
}
-(IBAction)showPicker:(id)sender
{
[UIView animateWithDuration:0.3 animations:^{
_pickerView.frame = CGRectMake(_pickerView.frame.origin.x,
107, //Displays the view a little past the
//center ling of the screen
_pickerView.frame.size.width,
_pickerView.frame.size.height);
}];
}
And for your viewDidLoad just call "closePicker" to have the view hidden on load
In a scrollView based application, showing and hiding UIPickerView could be a tough issue as it is relatively hard to pin it to the bottom of the visible screen rectangle. You can do it easily with the following code.
let alertController = UIAlertController(title: title, message: "\n\n\n\n\n\n\n\n\n\n", preferredStyle: .ActionSheet)
alertController.view.addSubview(pickerView)
alertController.addAction(UIAlertAction(title: "OK", style: .Cancel) { action in
})
self.presentViewController(alertController, animated: true, completion: nil)
To summarize, you create an UIAlertController with an empty message. In order to make the alertController to have the size of your pickerView, you give the message neccessary number of line breaks. And lastly you add your pickerView as a subview of alertController.view
You then follow the selected pickerView rows with the UIPickerViewDelegate methods.
I looked everywhere for a clean way to hide and show (toggle) UIPickerView using a single button item and only found bits and pieces. For those looking to do the same, here's my working result via a basic conditional statement.
ViewController.m
- (IBAction)animatePicker {
if ([self.userSelection.title isEqualToString: (NSString *)@"Select"]) {
_userPicker.hidden = NO;
UIPickerView *pickerView = [[UIPickerView alloc] init]; // default frame is set
float pvHeight = pickerView.frame.size.height;
float y = [[UIScreen mainScreen] bounds].size.height - (pvHeight); // the root view of view controller
[UIView animateWithDuration:0.25f delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
self.userPicker.frame = CGRectMake(0 , y, pickerView.frame.size.width, pvHeight);
} completion:nil];
} else if ([self.userSelection.title isEqualToString: (NSString *)@"Done"]) {
UIPickerView *pickerView = [[UIPickerView alloc] init]; // default frame is set
float pvHeight = pickerView.frame.size.height;
float y = [[UIScreen mainScreen] bounds].size.height - (pvHeight * -2); // the root view of view controller
[UIView animateWithDuration:0.25f delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
self.userPicker.frame = CGRectMake(0 , y, pickerView.frame.size.width, pvHeight);
} completion:nil];
self.userSelection.title = @"Select";
}
}
So here's what's going on here: I've got a button item called "userSelection" with a title of "Select" and a hidden UIPickerView called "userPicker" (to hide, just copy the bit about "_userPicker.hidden", paste it in your picker declaration, and set the boolean to YES). The button item is connected to the above action. On load (i.e. when the button's title says "Select"), it unhides the picker and animates it into view. You can use the animateWithDuration and delay options to control that function, but these settings seem pretty natural to me.
Then I've got this method changing the button's title to "Done" when something's been selected. I'm positive there's a cleaner way to do this bit, but the switch method gives me some freedom in case I want to make UI changes later.
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component{
NSLog(@"Selected Row %ld", (long)row);
switch(row)
{
case 0:
self.userSelection.title = @"Done";
break;
case 1:
self.userSelection.title = @"Done";
break;
case 2:
self.userSelection.title = @"Done";
break;
case 3:
self.userSelection.title = @"Done";
break;
case 4:
self.userSelection.title = @"Done";
break;
case 5:
self.userSelection.title = @"Done";
break;
}
}
Finally, the action closes with an "else if" that says when the button says "Done", hide the picker with the reverse animation (same code, but with "pvHeight * -2") and then sets the button's title back to "Select" which serves to complete the loop of the whole action.
Probably an easier way for the pros out there, but for the folks who are new to this stuff, like me, this made the most logical sense. Plus it works, so that's always a bonus!
Below is the sample code to hide and show of UIPickerView
with animation:-
//For Displaying
-(void)showPickerView{
self.pickerSheet = [UIAlertController alertControllerWithTitle:@"Select font" message:nil preferredStyle:UIAlertControllerStyleActionSheet];
self.pickerView = [[UIPickerView alloc]initWithFrame:CGRectZero];
self.pickerView.dataSource = self;
self.pickerView.delegate = self;
self.pickerView.showsSelectionIndicator = YES;
[self.pickerView selectRow:1 inComponent:0 animated:YES];
[self.pickerSheet.view addSubview:self.pickerView];
self.pickerView.translatesAutoresizingMaskIntoConstraints = NO;
UIView *view = self.pickerView;
[self.pickerSheet.view addConstraints:[NSLayoutConstraint
constraintsWithVisualFormat:@"V:|[view]|"
options:0l
metrics:nil
views:NSDictionaryOfVariableBindings(view)]];
[self.pickerSheet.view addConstraints:[NSLayoutConstraint
constraintsWithVisualFormat:@"H:|[view]|"
options:0l
metrics:nil
views:NSDictionaryOfVariableBindings(view)]];
[self presentViewController:self.pickerSheet animated:YES completion:^{
}];
}
//For hiding
-(void)hidePickerView{
[self.pickerSheet dismissViewControllerAnimated:YES completion:^{
}];
}
精彩评论