IQKeyboardManager with UIDatePicker - ios

I've implemented the IQKeyboardManager framework to make the keyboard handle easier. It works very fine, except for one thing :
There're some UItextField controls in my app which open a UIDatePicker in place of a default keyboard (e.g. number pad, decimal pad, ASCII capable, etc.).
Here's a code sample with the graphical result :
// Create the datePicker
UIDatePicker *birthdayDatePicker = [UIDatePicker new];
[birthdayDatePicker setDatePickerMode:UIDatePickerModeDate];
// Assign the datePicker to the textField
[myTextField setInputView:birthdayDatePicker];
My question is :
Is it possible to handle the action on the "OK" button to fill the field "Date de naissance" ?
EDIT :
For the ones who want to know how I solved my problem :
in my .h, I imported IQDropDownTextField.h :
#import "IQDropDownTextField.h"
in the .h, I changed the type of my UITextField to IQDropDownTextField :
#property (weak, nonatomic) IBOutlet IQDropDownTextField *myTextField;
select your field in Interface Builder or in your .xib, and show the Identity Inspector : change your field's class to IQDropDownTextField.
Note according to Mohd Iftekhar Qurashi comment : the two next points can be avoided with the following code :
// Set myTextField's dropDownMode to IQDropDownModeDatePicker
myTextField.dropDownMode = IQDropDownModeDatePicker;
// Create a dateFormatter
NSDateFormatter *df = [NSDateFormatter new];
[df setDateFormat:#"dd/MM/yyyy"];
// Assign the previously created dateFormatter to myTextField
myTextField.dateFormatter = df;
// Assign a minimum date and/or maximum date if you want
myTextField.minimumDate = [NSDate date];
myTextField.maximumDate = [NSDate date];
// That's all !
in the .m, I added the setCustomDoneTarget:action: method :
// Create the datePicker
UIDatePicker *birthdayDatePicker = [UIDatePicker new];
[birthdayDatePicker setDatePickerMode:UIDatePickerModeDate];
// Assign the datePicker to the textField
[myTextField setInputView:birthdayDatePicker];
// Just added this line
[myTextField setCustomDoneTarget:self action:#selector(doneAction:)];
in the .m, I added the doneAction: method :
- (void)doneAction:(UITextField *)textField
{
[myTextField setText:[DateHelper getStringFromDate:birthdayDatePicker.date format:#"dd/MM/yyyy" useGmt:NO]]; // getStringFromDate:format:useGmt: is a method to convert a NSDate to a NSString according to the date format I want
}

You can now add customised selector(please refer 'IQUIView+IQKeyboardToolbar.h') for previous/next/done to get notify. Note that custom selector doesn't affect the native functionality of previous/next/done, it's just used for callback purpose only. For detail documentation please refer 'IQUIView+IQKeyboardToolbar.h', for 'how to use?' please refer 'TextFieldViewController.m'.

Related

Date-derived field not updating with core data change

I have a view controller that implements UITextViewDelegate, UITextFieldDelegate, and NSFetchedResultsControllerDelegate. It is a UIViewController, not a table VC. Nor is there a table in it.
When I make a change to the Core Data store in another view controller, most text fields and text views in the first VC update However, I have another text field that shows the date and is derived from `NSDateFormatter, based on a date attribute in Core Data. It is hidden when nil and when the value is no longer nil, the code to unhide it is not working.
There isn't any code in the VC that says the text views and text fields that DO update specifically are delegates of anything. They just update naturally.
Perhaps the delegate was set in storyboard, but I don't remember and don't know a way to check what delegates are set in storyboard.
Is there a special date delegate? Or how would I get this text field derived from NSDateFormatter to update?
EDIT:
This is where the date is displayed in a method called updateInterface called within viewWillAppear
//Here is an example of a label that does update when data changes.
self.nameLabel.text = self.item.name; //this sets name...It updates when name is changed.
//Here is the data label that is not changing from hidden to not hidden.
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"EEEE MMMM d, YYYY 'at' h:mma"];
NSString *date = [dateFormatter stringFromDate:self.item.date];
if (self.item.date!=nil) {
self.dateLabel.text =date;
else {
self.dateLabel.hidden = YES;
}

Passing UITextField Value to Function Within View

I'm just beginning with XCode and coding for iOS, have the following problem. I want to add a function that sets UITextField values in the ViewController based around the value from a UIStepper. The code actually handles formatting three UITextFields, cut it to one to shorten the example. This code works fine:
- (IBAction)Temp_Stepper_Changed:(UIStepper *)sender {
integer_t stepperValue = (integer_t) sender.value;
NSString *temp_format = [[NSString alloc]
initWithFormat: #"%%.%df",stepperValue];
double fahrenheit = [_TempF_Text.text doubleValue];
NSString *FresultString = [[NSString alloc]
initWithFormat: temp_format,fahrenheit];
_TempF_Text.text = FresultString;
}
I have several places I want to do this, so want to create a function to call, and so I put this function into the view controller's .m file:
void Temp_Text_Update (double F_Temp){
NSString *FresultString = [[NSString alloc]
initWithFormat: #"%.2f",F_Temp];
_TempF_Text.text = FresultString;
}
The function won't compile, results in error:
use of undeclared identifier '_TempF_Text'
Without the line, it compiles fine, can call the function, pass values, etc. I had assumed (remember, beginning at this) as the UIStepper had _TempF_Text in it's scope, the function being in the same .m file would as well. Is there some magic happening behind the scenes that allows the IBAction type calls to access any value from the ViewController items, but my function is missing said magic? I'll also need the UIStepper value to complete the function. This was built using Storyboard, control-drag for outlets and actions, header file is:
#interface TemperatureViewController : UIViewController
#property (weak, nonatomic) IBOutlet UITextField *TempF_Text;
#property (weak, nonatomic) IBOutlet UIStepper *Temp_Stepper;
- (IBAction)TempF_CnvButton:(id)sender;
- (IBAction)Temp_Stepper_Changed:(UIStepper *)sender;
I've spent a few hours searching, including this site, found references from one ViewController to another and so forth, but doesn't really match; tried a few things anyway, but nothing worked (though some yielded extra errors). I suspect it is so obvious and simple as to not be asked, but I've run out of ideas and any help would be appreciated.
To answer the specific question, the correct syntax for the signature you're trying to write would look like this:
- (void)Temp_Text_Update:(double)F_Temp {
This says we have a method named Temp_Text_Update: that takes a double parameter called F_Temp and doesn't return anything.
A more general solution would be to use NSNumberFormatter to go between strings and doubles in a locale sensitive way, something like this:
// get a double from a string
- (double)doubleFromString:(NSString *)string {
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setNumberStyle:NSNumberFormatterDecimalStyle];
NSNumber *number = [formatter numberFromString:string];
return [number doubleValue];
}
// get a string from a double:
- (NSString *)stringFromDouble:(double)aDouble {
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setNumberStyle:NSNumberFormatterDecimalStyle];
return [formatter stringFromNumber:[NSNumber numberWithDouble:aDouble]];
}
Then your computing functions would look like this:
NSString *text = self.someControlView.text;
double aDouble = [self doubleFromString:text];
// do computation on aDouble, resulting in
double result = // whatever
[self setOutputTextWithResult:result];
Finally, your method (better named):
- (void) setOutputTextWithResult:(double)result {
self.someControlView.text = [self stringFromDouble:result];
}
It's so short now, it almost doesn't need it's own method.

UIDatePicker not scrolling iOS

I do not know what to say but this bug has been haunting me for the last 2 days and I cannot get it to work.
I want to add a UIDatePicker to my view. But for some reason it is not scrolling. I just dragged and dropped the control but without any luck. I checked my view is user-interaction enabled. I even created a dummy view controller which only has a picked in it and made it the initial view controller, still no scrolling happening.
All other interactions are fine.
I created a new project from scratch and simply dropped a picker in its view and tested. It scrolled!!! Not sure why the one in my app is not.
I know you will ask for code, but there is no code here. Jut adding the picker in an initial vc and no action is happening.
Any idea what could be wrong? where i should look?
Cheers
Try to use following code
#import "DatePickerViewController.h"
#interface DatePickerViewController ()
#end
#implementation DatePickerViewController
-(void)getSelection:(id)sender
{
NSLocale *usLocale = [[NSLocale alloc]
initWithLocaleIdentifier:#"en_US"];
NSDate *pickerDate = [_datePicker date];
NSString *selectionString = [[NSString alloc]
initWithFormat:#"%#",
[pickerDate descriptionWithLocale:usLocale]];
_dateLabel.text = selectionString;
}
.
.
.
#end

iOS SDK: about using properties when creating objects programmatically?

okay below is a standard example of creating a datepicker
- (void)viewDidLoad {
CGRect pickerFrame = CGRectMake(0,250,100,100);
UIDatePicker *myPicker = [[UIDatePicker alloc] initWithFrame:pickerFrame];
[myPicker addTarget:self action:#selector(pickerChanged:) forControlEvents:UIControlEventValueChanged];
[self.view addSubview:myPicker];
[myPicker release];
}
- (void)pickerChanged:(id)sender
{
NSLog(#"value: %#",[sender date]);
}
this is all good and well. I'm a little used to creating elements in IB so when I create an object programatically I'm not sure how to access the data.
What I mean is.. should I assign myPicker to a class property and then access it as _myPicker?
Or lets say I want to access the date inside of the pickerChanged method without calling another method. Should I assign an NSDate property and re-assign it every time the picker is changed?
I ran into some memory issues when I was trying to do it that way. I had another method grabbing _theDate, and it probably tried to access it at the same time pickerChanged was modifying it?
Anyway, what I'm getting at is "whats the proper workflow when creating things like action sheets, and pickers programmatically". When these things are changed, how should the resulting data be saved so the rest of the class can access it?
Bonus question:
Is there a difference between this?
for(UILabel *myLabel in view.subviews){
NSLog(myLabel.text);
}
and this? Do I need to check the class all the time if i know my view only contains a certain kind of object?
for((id) myLabel in view.subviews){
if([myLabel isKindOfClass:[UILabel class]){
UILabel *theLabel = myLabel;
NSLog(myLabel.text);
}
}
Generally, you will just define properties if you'll need to access them more than once. You can do this in the .m file's interface:
#interface MyObject()
#property (weak, nonatomic) UIDatePicker *myPicker;
#end
You will then be able to access it by either _myPicker or self.myPicker.
You shouldn't need another NSDate property in your class because you can access the set date at any time:
_myPicker.date
For your last question: the latter of the two is merely extra sanity checks. While you're writing your own code, and you should know what subviews you're adding in, it can't hurt to double check the type of the subviews incase anything should go wrong and you try to access selectors that don't exist. This is a larger programming question though and not necessarily objective-c or iOS specific.
The documented approach is to intercept the UIControlEventValueChanged event, as per your example.
You would then typically copy the [sender date] value to a property in your pickerChanged: method.
If the user hits a save button, then the object that presented the view containing the picker should be able to retrieve the selected date via the property.
It's not considered good practice to use isKindOfClass:. You should structure your code such that you always know what class you're dealing with.
Also, you should really switch to ARC so you don't need to worry about calling release
You need to declare a UIDatePicker property to hold one instance of your child controller
This is what you need to add in your .h file:
#property (strong, nonatomic) UIDatePicker *myPicker;
And then in your .m file you need to add a data source method for this date picker. something like what rdelmar has instructed above:
self.myPicker = [[UIDatePicker alloc] init];

passing data between UIViewControllers from UIDatePicker

Let me begin to tell you that I am new to Objective C. I have just finished Big Nerd Ranch's book and i want to create a real simple and basic app to learn more.
My idea was to create an app that will calculate the weeks between 2 dates. I have created a class for that and tested it. That works.
As you can see below, I have created to views (programmatically), One with the dates and the other will become visible when you click on start or end date.
If you select a date and click on the button 'calculate weeks', you will go back to the first view.
No my big question is, how do I get this selected value back to my main screen? I have tried several possibilities and search the web for information, but I couldn't get is to work.
I know this should be real easy, but for me at this moment it isn't. :-)
I have created a NSMutableArray that contains the values "Start date" and "End date". My idea was to add the value of the UILabel from the SelectDateView to this array.
I have created a property In the inputview #property (readwrite, retain) NSMutableArray *datesArray; for that.
in the selectDateViewController i have created another property #property (nonatomic, assign) BITInputViewController *ivc; so I (in my opinion) can add a value to datesArray.
When I select a date this method is called, it works for the UILabel on SelectDateView, but doesn't do anything with the datesArray.
- (void)LabelChange:(id)sender{
NSDateFormatter *df = [[NSDateFormatter alloc] init];
df.dateStyle = NSDateFormatterMediumStyle;
dateLabel.text = [NSString stringWithFormat:#"%#",
[df stringFromDate:datePicker.date]];
[ivc.datesArray addObject:dateLabel.text];
if (ivc.datesArray) {
for (NSString *d in ivc.datesArray) {
NSLog(#"This is in datesArray %#",d);
}
}else NSLog(#"!ivc.datesArray");
}
When I test the app and select a date, I always see "!ivc.datesArray" in the log file.
I also do this check of ivc.datesArray in -(void)viewWillAppear:(BOOL)animated
and here I see the current date, as I set this date in - (void)viewDidLoad
with this dateLabel.text = [NSString stringWithFormat:#"%#",[df stringFromDate:[NSDate date]]];
(When I print out the array in the inputview, it does show start date and end date, but not the selected date. )
Hopefully someone can give me a few pointers on this.
declare a NSString* date above the #interface in your view1.m file and the create a method in tht first class it should be something like
-(void)passDate:(NSString *)dateString
{
date = [NSString stringWithFormat:#"%#",dateString];
}
and in your second class create object of first class like
View1 * vc = [[View1 alloc]init];
[vc passDate:df];
Hope it works. You have to declare NSString before the #interface and no property and synthesize.

Resources