Created
January 14, 2013 10:50
-
-
Save danielctull/4529248 to your computer and use it in GitHub Desktop.
Controller that displays a picker view as an input view to a text field on iPhone or in a popover on iPad.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // | |
| // RQSTextFieldOptionsController.h | |
| // Requests | |
| // | |
| // Created by Daniel Tull on 03.10.2012. | |
| // Copyright (c) 2012 Daniel Tull. All rights reserved. | |
| // | |
| #import <UIKit/UIKit.h> | |
| @interface RQSTextFieldOptionsController : UIView | |
| @property (nonatomic, weak) IBOutlet UITextField *textField; | |
| @property (nonatomic, copy) NSArray *options; | |
| @property (nonatomic, assign) UIPopoverArrowDirection popoverArrowDirection; | |
| @end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // | |
| // RQSTextFieldOptionsController.m | |
| // Requests | |
| // | |
| // Created by Daniel Tull on 03.10.2012. | |
| // Copyright (c) 2012 Daniel Tull. All rights reserved. | |
| // | |
| #import "RQSTextFieldOptionsController.h" | |
| #import <objc/runtime.h> | |
| void *RQSTextFieldOptionsControllerKey = &RQSTextFieldOptionsControllerKey; | |
| @interface RQSTextFieldOptionsController () <UIPickerViewDataSource, UIPickerViewDelegate, UIPopoverControllerDelegate> | |
| @property (nonatomic, strong) UIPickerView *pickerView; | |
| @end | |
| @implementation RQSTextFieldOptionsController { | |
| __strong UIPopoverController *_popoverController; | |
| } | |
| - (void)dealloc { | |
| [self.textField removeTarget:self action:@selector(textFieldEditingChanged:) forControlEvents:UIControlEventEditingChanged]; | |
| UIUserInterfaceIdiom idiom = [[UIDevice currentDevice] userInterfaceIdiom]; | |
| if (idiom == UIUserInterfaceIdiomPad) { | |
| [self.textField removeTarget:self action:@selector(textFieldEditingDidBegin:) forControlEvents:UIControlEventEditingDidBegin]; | |
| [self.textField removeTarget:self action:@selector(textFieldEditingDidEndOnExit:) forControlEvents:UIControlEventEditingDidEnd]; | |
| } | |
| } | |
| - (id)init { | |
| self = [super init]; | |
| if (!self) return nil; | |
| _popoverArrowDirection = UIPopoverArrowDirectionAny; | |
| return self; | |
| } | |
| - (void)setTextField:(UITextField *)textField { | |
| objc_setAssociatedObject(_textField, RQSTextFieldOptionsControllerKey, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC); | |
| _textField = textField; | |
| objc_setAssociatedObject(_textField, RQSTextFieldOptionsControllerKey, self, OBJC_ASSOCIATION_RETAIN_NONATOMIC); | |
| [_textField addTarget:self action:@selector(textFieldEditingChanged:) forControlEvents:UIControlEventEditingChanged]; | |
| [self _setDefaultOption]; | |
| UIUserInterfaceIdiom idiom = [[UIDevice currentDevice] userInterfaceIdiom]; | |
| if (idiom == UIUserInterfaceIdiomPad) { | |
| _textField.inputView = [UIView new]; | |
| [_textField addTarget:self action:@selector(textFieldEditingDidBegin:) forControlEvents:UIControlEventEditingDidBegin]; | |
| [_textField addTarget:self action:@selector(textFieldEditingDidEndOnExit:) forControlEvents:UIControlEventEditingDidEnd]; | |
| } else if (idiom == UIUserInterfaceIdiomPhone) | |
| _textField.inputView = self.pickerView; | |
| } | |
| - (void)setOptions:(NSArray *)options { | |
| _options = [options copy]; | |
| [self _setDefaultOption]; | |
| } | |
| - (UIPickerView *)pickerView { | |
| if (!_pickerView) { | |
| _pickerView = [UIPickerView new]; | |
| _pickerView.dataSource = self; | |
| _pickerView.delegate = self; | |
| _pickerView.showsSelectionIndicator = YES; | |
| [_pickerView selectRow:[self.options indexOfObject:self.textField.text] inComponent:0 animated:NO]; | |
| } | |
| return _pickerView; | |
| } | |
| - (IBAction)textFieldEditingChanged:(id)sender { | |
| self.textField.text = [self pickerView:_pickerView titleForRow:[_pickerView selectedRowInComponent:0] forComponent:0]; | |
| [self _sendTextFieldControlEvents]; | |
| } | |
| - (IBAction)textFieldEditingDidEndOnExit:(id)sender { | |
| [_popoverController dismissPopoverAnimated:YES]; | |
| _popoverController = nil; | |
| } | |
| - (IBAction)textFieldEditingDidBegin:(id)sender { | |
| UIPickerView *pickerView = self.pickerView; | |
| UIViewController *pickerViewController = [UIViewController new]; | |
| pickerViewController.view.frame = pickerView.bounds; | |
| [pickerViewController.view addSubview:pickerView]; | |
| _popoverController = [[UIPopoverController alloc] initWithContentViewController:pickerViewController]; | |
| _popoverController.popoverContentSize = pickerView.bounds.size; | |
| _popoverController.delegate = self; | |
| _popoverController.passthroughViews = [self _allControlSubviews:[self _ancestorView:self.textField]]; | |
| [_popoverController presentPopoverFromRect:self.textField.frame inView:self.textField.superview permittedArrowDirections:self.popoverArrowDirection animated:YES]; | |
| } | |
| #pragma mark - Internal | |
| - (UIView *)_ancestorView:(UIView *)view { | |
| while (view.superview) | |
| view = view.superview; | |
| return view; | |
| } | |
| - (NSArray *)_allControlSubviews:(UIView *)view { | |
| NSMutableArray *subviews = [NSMutableArray new]; | |
| if ([view isKindOfClass:[UIControl class]] || [view isKindOfClass:[UITableViewCell class]]) | |
| [subviews addObject:view]; | |
| [view.subviews enumerateObjectsUsingBlock:^(UIView *v, NSUInteger idx, BOOL *stop) { | |
| [subviews addObjectsFromArray:[self _allControlSubviews:v]]; | |
| }]; | |
| return subviews; | |
| } | |
| - (void)_setDefaultOption { | |
| if ([self.options count] == 0) return; | |
| if ([self.textField.text length] > 0 && [self.options containsObject:self.textField.text]) return; | |
| self.textField.text = self.options[0]; | |
| [self _sendTextFieldControlEvents]; | |
| } | |
| - (void)_sendTextFieldControlEvents { | |
| [self.textField removeTarget:self action:@selector(textFieldEditingChanged:) forControlEvents:UIControlEventEditingChanged]; | |
| [self.textField sendActionsForControlEvents:UIControlEventEditingChanged]; | |
| [self.textField addTarget:self action:@selector(textFieldEditingChanged:) forControlEvents:UIControlEventEditingChanged]; | |
| } | |
| #pragma mark - UIPopoverControllerDelegate | |
| - (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController { | |
| [self.textField resignFirstResponder]; | |
| } | |
| #pragma mark - UIPickerViewDataSource | |
| - (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView { | |
| return 1; | |
| } | |
| - (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component { | |
| return [self.options count]; | |
| } | |
| #pragma mark - UIPickerViewDelegate | |
| - (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component { | |
| return self.options[row]; | |
| } | |
| - (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component { | |
| self.textField.text = self.options[row]; | |
| [self _sendTextFieldControlEvents]; | |
| } | |
| @end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment