Skip to content

Instantly share code, notes, and snippets.

@danielctull
Created January 14, 2013 10:50
Show Gist options
  • Select an option

  • Save danielctull/4529248 to your computer and use it in GitHub Desktop.

Select an option

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.
//
// 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
//
// 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