XCode: Displaying a UIDatePicker when user clicks on UITextbox

泄露秘密 提交于 2019-11-30 04:34:24

Showing a UIDatePicker for the inputView of a UITextField is relatively hard compared to showing a keyboard, but relatively easy compared to the trouble you've had.

One of the first problems I noticed with your code, and it's a very common problem with those new to iOS/Mac development, is that you are attempting to set the property of an object that doesn't exist yet. Putting "self.dueDate.inputView = datePicker;" in your initWithNibName:bundle: will not work because the view has not yet loaded, and dueDate is part of your view. In objective-c an object is instantiated with alloc & init. Init is the first real method call to any object. At this point in your view controller's life the view has not been created yet. The method call where self.dueDate.inputView = datePicker; belongs is in the viewDidLoad method. It is called exactly when it sounds like it's called, and your dueDate property will be properly loaded at that point. There is no need to use a custom subclass of UITextField to display a date picking view for for your text field. Here is a very basic example of a custom input view class:

ExampleBasicDateInputView.h:

#import <UIKit/UIKit.h>

@interface ExampleBasicDateInputView : UIView
@property (strong,nonatomic) UIDatePicker *datePicker;
@end

ExampleBasicDateInputView.m:

#import "ExampleBasicDateInputView.h"

@implementation ExampleBasicDateInputView{
    UITextField *_inputField; // ivar to store the textfield currently being edited
}
@synthesize datePicker = _datePicker;
// TARGET METHODS
-(void)pickerValueChanged:(UIDatePicker *)picker{
    _inputField.text = self.datePicker.date.description; // set text to date description
}
-(void)viewDoubleTapped:(UITapGestureRecognizer *)tapGR{
    [_inputField resignFirstResponder]; // upon double-tap dismiss picker
}
-(void)textFieldBeganEditing:(NSNotification *)note{
    _inputField = note.object; // set ivar to current first responder
}
-(void)textFieldEndedEditing:(NSNotification *)note{
    _inputField = nil; // the first responder ended editing CRITICAL:avoids retain cycle
}
// INITI METHODS
-(void)initializationCodeMethod{
    _datePicker = [[UIDatePicker alloc] initWithFrame:CGRectMake(0, 0, 320, 0)];// All pickers have preset height
    self.bounds = _datePicker.frame; // Make our view same size as picker
    [self addSubview:_datePicker];
    [_datePicker addTarget:self action:@selector(pickerValueChanged:) forControlEvents:UIControlEventValueChanged]; // register to be notified when the value changes
        // As an example we'll use a tap gesture recognizer to dismiss on a double-tap
    UITapGestureRecognizer *tapGR = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(viewDoubleTapped:)];
    tapGR.numberOfTapsRequired = 2; // Limit to double-taps
    [self addGestureRecognizer:tapGR];
    NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
    [center addObserver:self selector:@selector(textFieldBeganEditing:) name:UITextFieldTextDidBeginEditingNotification object:nil]; // Ask to be informed when any textfield begins editing
    [center addObserver:self selector:@selector(textFieldEndedEditing:) name:UITextFieldTextDidEndEditingNotification object:nil]; // Ask to be informed when any textfield ends editing
}
-(id)init{
    if ((self = [super init])){
        [self initializationCodeMethod];
    }
    return self;
}
-(id)initWithFrame:(CGRect)frame{
    if ((self = [super initWithFrame:frame])){
        [self initializationCodeMethod];
    }
    return self;
}
-(id)initWithCoder:(NSCoder *)aDecoder{
    if ((self = [super initWithCoder:aDecoder])){
        [self initializationCodeMethod];
    }
    return self;
}
-(void)dealloc{
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UITextFieldTextDidBeginEditingNotification object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UITextFieldTextDidEndEditingNotification object:nil];
}
@end

Then in view did load you would use this class like this:

ExampleBasicDateInputView *dateEntryView = [[ExampleBasicDateInputView alloc] init];
self.dueDate.inputView = datePickerView;

And as you see in the .h file we've exposed the date picker instance as a property so you can set the style. etc. like so:

dateEntryView.datePicker.datePickerMode = UIDatePickerModeDate;

Obviously this is a very basic example, but I think it shows what can be done.

I had the same issue using Storyboard. Here is how I resolved it:

Overview: I alloc and initialize my UIDatePicker property in viewDidLoad:. I then set the inputView property of my textfield to my datepicker property.

Here is my code: In TripViewController.h:

@property (nonatomic,strong) IBOutlet UIDatePicker *datePicker;

In TripViewController.m:

@synthesize datePicker;
...
-(void)viewDidLoad {
...
self.datePicker = [[UIDatePicker alloc]init];
[self.datePicker addTarget:self action:@selector(dateChanged) forControlEvents:UIControlEventValueChanged];
self.dateField.inputView = self.datePicker;
}

I then implement my method, dateChanged so that whenever the date picker wheel stops moving, my textfield is updated.

- (void)dateChanged
{
NSDate *date = self.datePicker.date;
NSDateFormatter *dateFormat = [[NSDateFormatter alloc]init];
[dateFormat setDateStyle:NSDateFormatterMediumStyle];
self.dateField.text = [dateFormat stringFromDate:date];
}

add UITextField's delegate in .h file to call this function when touched. then use the text field's tag value to determine what you want to do when the field is selected.

-(BOOL) textFieldShouldBeginEditing:(UITextField *) textField 
{
    activeTextField = textField;

    if (textField.tag == 1) 
    {
        self.datePicker.datePickerMode = UIDatePickerModeDate;
        self.isDatePicker = TRUE;
        self.tempTextField = textField;
        [self showPicker];
        return NO;
    }
    else if (textField.tag == 2) 
    {
        self.datePicker.datePickerMode = UIDatePickerModeTime;
        self.isDatePicker = TRUE;
        self.tempTextField = textField;
        [self showPicker];

        return NO;
    }
    else if (textField.tag == 3)
    {
        self.isDatePicker = FALSE;
        self.tempTextField = textField;
        [self showPicker];
        return NO;
    }
    else
    {
        self.tempTextField = textField;
        return YES;
    }
}

It is very easy. Defines delegate TextField (UITextFieldDelegate) in the .h in the viewDidLoad .m

myTextField.setDelegate = self;

In the same viewDidLoad associates the datePicker to myTextField.

myTextField.inputView = myDatePicker;

You can also do anime, but this is the easiest way.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!