Having a slight problem here.
The (IBAction) method I have set up for UITextfields EditingDidChange is not being called when the textField is changed when using a UIPickerView as input.
However, it works fine when using keyboard input.
Does the UIPickerView not send out its current selection until it's dismissed or something?
An alternative is to probably use the UIPickerView method, didSelectRow to perform the updates I'm after.
Is there there a unique way I'm unaware of that will get this to work how I want?
I think that you have something like this to setup your text field:
self.citys = #[#"Buenos Aires", #"Bahia Blanca", #"Azul",#"Pigue"];
self.namePicker = [[UIPickerView alloc] init];
self.namePicker.delegate = self;
self.namePicker.dataSource = self;
self.namePicker.showsSelectionIndicator = YES;
self.accessoryView = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];
UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:#selector(onNameSelection)];
[self.accessoryView setItems:[NSArray arrayWithObject:doneButton]];
self.textField.inputView = self.namePicker;
self.textField.inputAccessoryView = self.accessoryView;
And something like this to set the text when the user finish the selection:
- (void) onNameSelection{
NSInteger row = [self.namePicker selectedRowInComponent:0];
self.textField.text = [self.citys objectAtIndex:row];
[self.textField resignFirstResponder];
}
So... You don't need the action EditingChanged, because you know when the textfield.text is changed.
Maybe you also have something like this to change the text while the user select row in the picker:
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component{
self.textField.text = [self.citys objectAtIndex:row];
}
Again, you know when the textfield.text is changed.
So... Because YOU are the responsible of the changes on the textfield.text YOU are the responsible of call the function associated to the EditingChanged action.
Related
I'm new to iOS development and I have an assignment where I need to implement a a UITextfield which upon a tap, brings a country selector UIPickerView.
I went through some online tutorials and got it working somehow. But it shows some strange behaviour which I can't seem to figure out.
Some strange black bars are appearing, with the picker content visibly duplicated each time I scroll.
I believe I've made a mistake in my code, forgive my lack of knowledge but can't seem to figure out what is wrong in the code.
Could you please tell me what has gone wrong?
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
if ([textField isEqual:self.countryTextField]) {
countryPicker = [[UIPickerView alloc] initWithFrame:CGRectZero];
countryPicker.showsSelectionIndicator = YES;
self.countryPicker.delegate = self;
self.countryPicker.dataSource = self;
// [self.countryPicker reloadAllComponents];
countryPicker.showsSelectionIndicator = YES;
// [countryPicker init:self];
textField.inputView = countryPicker;
}
return YES;
}
- (UIView * ) pickerView: (UIPickerView * ) pickerView viewForRow: (NSInteger) row forComponent: (NSInteger) component reusingView: (UIView * ) view {
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, pickerView.frame.size.width, 44)];
label.text = [NSString stringWithFormat:#"%#", [[self.countries objectAtIndex:row] objectForKey:#"name"]];
[label setTextAlignment:UITextAlignmentLeft];
[label setBackgroundColor:[UIColor clearColor]];
[label setFont:[UIFont boldSystemFontOfSize:15]];
return label;
}
Might be initialising every time , instead of initialising at every time , Check whether the UIPicker is already initialised
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
if ([textField isEqual:self.countryTextField]) {
if(! countryPicker){
countryPicker = [[UIPickerView alloc] initWithFrame:CGRectZero];
countryPicker.showsSelectionIndicator = YES;
self.countryPicker.delegate = self;
self.countryPicker.dataSource = self;
countryPicker.showsSelectionIndicator = YES;
}
textField.inputView = countryPicker;
}
return YES;
}
It seems there are few things need to be changed in your code
1.Don't allocate memory to UIPickerView every time your text field get edited -textFieldShouldBeginEditing
if(self.countryPicker == nil)
{
self.countryPicker = [[UIPickerView alloc] initWithFrame:CGRectZero];
self.countryPicker.showsSelectionIndicator = YES;
self.countryPicker.delegate = self;
self.countryPicker.dataSource = self;
self.countryPicker.showsSelectionIndicator = YES;
}
2.Either use self.countrypicker -> class property or countrypicker don't use them interchangeably.
Well I finally found the issue. It was a silly mistake of defining a wrong number of components in numberOfComponentsInPickerView
I have a scene in which I want to use picker views to get the input for multiple text boxes. I want each picker view to have a toolbar with a "Done" button that dismisses the picker view. So far I have:
//toolbar with "Done" button for picker views
UIToolbar *pickerToolBar= [[UIToolbar alloc] initWithFrame:CGRectMake(0,0,320,44)];
[pickerToolBar setBarStyle:UIBarStyleBlackOpaque];
UIBarButtonItem *barButtonDone = [[UIBarButtonItem alloc] initWithTitle:#"Done"
style:UIBarButtonItemStyleBordered
target:self
action:#selector(doneWithPicker:)];
pickerToolBar.items = [[NSArray alloc] initWithObjects:barButtonDone,nil];
barButtonDone.tintColor=[UIColor blackColor];
//set up picker views
_pickerOne = [[UIPickerView alloc] init];
_pickerOne.dataSource = self;
_pickerOne.delegate = self;
self.textFieldOne.inputView = self.pickerOne;
self.textFieldOne.inputAccessoryView = pickerToolBar;
What I need is some way for the doneWithPicker method to figure out which text field is currently being edited and call resignFirstResponder.
Use the text field delegate to identify which field is active. (Make sure to set yourself up as the delegate)
#implementation WhateverViewController
{
UITextField *activeTextField;
}
...
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
activeTextField = textField;
}
Then, in the method that is called when your done button is tapped:
[activeTextField resignFirstResponder];
Wish you happy new year to all iOS developers.I want to display Blood group in UITextfield.
So I should took UIPickerview and append the Blood group list.My requirement is if user hit the UITextfiled the UIPickerview will be displayed and user select the blood group and it will reflect the blood group item in UITextfield.I am trying to do this functionality. But I have got some problem to display blood group value in UITextfield.The problem is for example if I click the A-ve blood group this will be displayed as it is in UITextfield.But if i click the A+ve group it will display like A ve instead of A+ve in UITextfield. This is my problem.Any body please help me. Thanks in advance.
The given below is my code.
//Bloodgroupviewcontroller.m
arrChooseServices=[[NSMutableArray alloc]initWithObjects:#"A+ve",#"A-ve",#"B+ve",#"B-ve",#"AB+ve",#"AB-ve",#"O+ve",#"O-ve", nil];
bloodGroup=[[UITextField alloc]initWithFrame:CGRectMake(150, 200, 120, 20)];
bloodGroup.borderStyle=UITextBorderStyleRoundedRect;
bloodGroup.backgroundColor=[UIColor clearColor];
bloodGroup.backgroundColor=[UIColor colorWithRed:0.662745 green:0.662745 blue:0.662745 alpha:0.5];
[bloodGroup setUserInteractionEnabled:NO];
bloodGroup.font=[UIFont systemFontOfSize:14.0];
bloodGroup.contentVerticalAlignment=UIControlContentVerticalAlignmentCenter;
bloodGroup.textAlignment=NSTextAlignmentCenter;
bloodGroup.delegate=self;
bloodGroup.inputView=self.chooseServicePicker;
bloodGroup.inputAccessoryView=self.accessoryView;
[self.view addSubview:bloodGroup];
-(UIPickerView *)chooseServicePicker
{
if(chooseServicePicker==nil)
{
chooseServicePicker=[[UIPickerView alloc]init];
chooseServicePicker.delegate=self;
chooseServicePicker.dataSource=self;
chooseServicePicker.showsSelectionIndicator=YES;
}
return chooseServicePicker;
}
-(UIToolbar *)accessoryView
{
if ( accessoryView == nil )
{
accessoryView = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, 320, 30)];
UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:#selector(onBloodGroupSelection)];
UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:#selector(cancel)];
accessoryView.items=[NSArray arrayWithObjects:doneButton,cancelButton, nil];
}
return accessoryView;
}
- (void)onBloodGroupSelection
{
NSInteger row = [self.chooseServicePicker selectedRowInComponent:0];
bloodGroup.text=[arrChooseServices objectAtIndex:row];
[bloodGroup resignFirstResponder];
}
About the + not displaying, I tested your code and it is working fine for me. I had to change the [bloodGroup setUserInteractionEnabled:NO]; to [bloodGroup setUserInteractionEnabled:YES]; to make the UITextField clickable. Still, try adding
- (void)pickerView:(UIPickerView *)pickerView didSelectRow: (NSInteger)row inComponent:(NSInteger)component{
bloodGroup.text = [arrChooseServices objectAtIndex:row] ;
}
to your code to make the UITextField change text when the UIPickerView is tapped.
Try this,
Add this method and other delegate method to ur class
- (void)pickerView:(UIPickerView *)pickerView didSelectRow: (NSInteger)row inComponent:(NSInteger)component
{
yourtextfield.text = [yourdataarray objectAtIndex:row] ;
}
Take a string globally as "selectedString"
-(void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
selectedString = yourdataarray[row];
}
-(void)onBloodGroupSelection
{
bloodGroup.text= selectedString;
[self.view endEditing:YES];
}
So I have a view controller that I created completely programmatically, I didn't use storyboard or a nib file. In it, I have a button, addNew that when pressed, it creates two UITextfields, one for a number, the other for a product, and places it where the "Add New"button was, and moves the button down. Instead of explaining it, here's some code :
-(IBAction)addProduct:(id)sender{
self.numOfProducts += 1;
//To keep track of how many times the button was pressed
NSLog(#"New Product Added");
NSLog(#"# of products: %d", self.numOfMaterials);
//The number textfield
self.numOfProduct = [[UITextField alloc]initWithFrame:CGRectMake(self.addNew.frame.origin.x, self.addNew.frame.origin.y, 70.0, 30.0)];
self.numOfProduct.delegate = self;
self.numOfProduct.textAlignment = NSTextAlignmentCenter;
[self.numOfProduct setPlaceholder:#"#"];
self.numOfProduct.borderStyle = UITextBorderStyleBezel;
self.numOfProduct.keyboardType = UIKeyboardTypeNumberPad;
//Added doneToolbar to close keypad
UIToolbar *doneToolbar = [[UIToolbar alloc]initWithFrame:CGRectMake(0, 0, 320, 50)];
doneToolbar.barStyle = UIBarStyleBlackTranslucent;
[doneToolbar setItems:[NSArray arrayWithObjects:
[[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil],
[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:#selector(doneNumPad)],
nil]];
[doneToolbar sizeToFit];
self.numOfMaterialNeeded.inputAccessoryView = doneToolbar;
//Product text field, places it next to numOfProduct text field
self.product = [[UITextField alloc]initWithFrame:CGRectMake(self.numOfProduct.frame.origin.x + 80, self.numOfProduct.frame.origin.y, 200.0, 30.0)];
self.product.delegate = self;
self.product.textAlignment = NSTextAlignmentCenter;
[self.product setPlaceholder:#"Product"];
self.product.borderStyle = UITextBorderStyleBezel;
self.product.autocapitalizationType = UITextAutocorrectionTypeNo;
self.product.keyboardType = UIKeyboardTypeDefault;
self.product.returnKeyType = UIReturnKeyDone;
self.product.clearButtonMode = UITextFieldViewModeWhileEditing;
//Places addNew below the newly created text fields
[self.addNew setFrame:CGRectMake(self.addNewMaterial.frame.origin.x, self.addNewMaterial.frame.origin.y + (self.addNewMaterial.frame.size.height + 10), self.addNewMaterial.frame.size.width, self.addNewMaterial.frame.size.height)];
// add text fields to the UIScrollView
[self.scrollView addSubview:self.numOfMaterialNeeded];
[self.scrollView addSubview:self.material];
}
//Called when done button is pressed for numOfProduct text field
-(void)doneNumPad{
[self.numOfProduct resignFirstResponder];
[self.product becomeFirstResponder];
//Save num in an array
[self.saveNumOfProduct addObject:self.numOfProduct.text];
for (int i = 0; i < [self.saveNumOfProduct count]; i++) {
NSLog(#"%# of ___", [self.saveNumOfProduct objectAtIndex:i]);
}
}
-(BOOL)textFieldShouldReturn:(UITextField *)textField{
[textField resignFirstResponder];
//Save product in an array
if (textField == self.product) { //
[self.saveNameOfProduct addObject:self.product.text];
}
return YES;
}
The code is working well and fine, BUT, I realized, if I have the self.numOfProduct textField as the first responder, and instead of pressing "Done", I press the self.product textField right away, it won't save the self.numOfProduct.text, same with the self.product.text, it won't save unless I press "Done". How can I do it so that I can efficiently save the text from the textfield property, no matter how many textfields I have on the screen? Is it possible? I appreciate any feedback! And if I haven't been clear enough, lemme know and I'll clear up whatever needs clearing!
I've found the answer! A lot easier than I thought it would be, I completely forgot about the (void)textFieldDidEndEditing:(UITextField *)textField function. All I had to do was save the text in that function, and it saves every time the textfield becomes the responder to another field OR when I press the done button.
Here is a screenshot of what I did till now:
So what I am trying to do is when you select "pick a name" Textfield I need a Picker to show up, with the input #"Jack".
Since iOS 3.2, UITextField supports the inputView property to assign a custom view to be used as a keyboard, which provides a way to display a UIPickerView:
You could use the inputView property of the UITextField, probably combined with the inputAccessoryView property. You assign your pickerView to the inputView property, and, to dismiss the picker, a done button to the inputAccessoryView property.
UIPickerView *myPickerView = [[UIPickerView alloc] init];
//myPickerView configuration here...
myTextField.inputView = myPickerView;
Like that. This will not give you a direct way to dismiss the view since your UIPickerView has no return button, which is why I recommend to use the inputAccessoryView property to display a toolbar with a done button (the bar is just for aesthetics, you might as well just use a UIButton object):
UIToolbar *myToolbar = [[UIToolbar alloc] initWithFrame:
CGRectMake(0,0, 320, 44)]; //should code with variables to support view resizing
UIBarButtonItem *doneButton =
[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone
target:self action:#selector(inputAccessoryViewDidFinish)];
//using default text field delegate method here, here you could call
//myTextField.resignFirstResponder to dismiss the views
[myToolbar setItems:[NSArray arrayWithObject: doneButton] animated:NO];
myTextField.inputAccessoryView = myToolbar;
I use this and find this a lot cleaner than adding a subview and animating the UIPicker
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
responder = textField;
if ([textField isEqual:self.txtBirthday]) {
UIDatePicker *datepicker = [[UIDatePicker alloc] initWithFrame:CGRectZero];
[datepicker setDatePickerMode:UIDatePickerModeDate];
textField.inputView = datepicker;
}
return YES;
}
it will work for you .. i have edited it .and for that you have to set delegate for textfield. and create a UIPIckrView in NIb file.
- (BOOL) textFieldShouldBeginEditing:(UITextView *)textView
{
pickrView.frame = CGRectMake(0, 500, pickrView.frame.size.width, pickrView.frame.size.height);
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:.50];
[UIView setAnimationDelegate:self];
pickrView.frame = CGRectMake(0, 200, pickrView.frame.size.width, pickrView.frame.size.height);
[self.view addSubview:pickrView];
[UIView commitAnimations];
return NO;
}
Well, you could rely on the UITextFieldDelegate to handle this kind of functionality.
Inside the
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
is where you would set the text of your current UITextField as well as initializing and showing the UIPickerView.
Important notice:
You might also want to conform to the UIPickerViewDelegate.
HTH
Swift:
internal var textFieldHandlerToolBar: UIToolbar = {
let tb = UIToolbar.init(frame: CGRect.init(origin: .zero, size: CGSize.init(width: UIScreen.main.bounds.width, height: 44.0)))
let doneBarButton = UIBarButtonItem.init(title: "Done", style: UIBarButtonItemStyle.done, target: self, action: #selector(actionDonePickerSelection))
tb.setItems([doneBarButton], animated: false)
return tb
}()
internal var pickerView: UIPickerView = {
let pv = UIPickerView.init()
return pv
}()
#objc internal func actionDonePickerSelection() {
textField.resignFirstResponder()
}
override func viewDidLoad() {
super.viewDidLoad()
self.pickerView.delegate = self
self.pickerView.datasource = self
}
Use it like this:
textField.inputAccessoryView = self.textFieldHandlerToolBar
textField.inputView = self.pickerView
What you can do is, create a UIButton with custom type on UITextField. Both having equal sizes. On the touch of button you can show UIPickerView.
http://tmblr.co/ZjkSZteCOUBS
I have the code and everything laid out in my blog to do this exactly. But below, I have the basic concept laid out.
Basically the solution involves an opensource project called ActionSheetPicker on github, and implementing the function textFieldShouldBeginEditing on the UITextFieldDelegate. You can dismiss the keyboard there and provide a UIPickerView instead. The basic code is listed here:
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
// We are now showing the UIPickerViewer instead
// Close the keypad if it is showing
[self.superview endEditing:YES];
// Function to show the picker view
[self showPickerViewer :array :pickerTitle];
// Return no so that no cursor is shown in the text box
return NO;
}
ViewController.h
#interface ChangeCurrencyVC : UIViewController <UIPickerViewDataSource, UIPickerViewDelegate>
{
NSArray *availableCurreniesArray;
}
#property (weak, nonatomic) IBOutlet UITextField *chooseCurrencyTxtFldRef;
ViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
availableCurreniesArray = #[#"Indian Rupee", #"US Dollar", #"European Union Euro", #"Canadian Dollar", #"Australian Dollar", #"Singapore Dollar", #"British Pound", #"Japanese Yen"];
// Do any additional setup after loading the view.
[self pickerview:self];
}
#pragma mark - picker view Custom Method
-(void)pickerview:(id)sender{
UIPickerView *pickerView = [[UIPickerView alloc] initWithFrame:CGRectMake(0, 0, 0, 0)];
pickerView.showsSelectionIndicator = YES;
pickerView.dataSource = self;
pickerView.delegate = self;
// set change the inputView (default is keyboard) to UIPickerView
self.chooseCurrencyTxtFldRef.inputView = pickerView;
// add a toolbar with Cancel & Done button
UIToolbar *toolBar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];
toolBar.barStyle = UIBarStyleBlackOpaque;
UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:#selector(doneTouched:)];
UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:#selector(cancelTouched:)];
// the middle button is to make the Done button align to right
[toolBar setItems:[NSArray arrayWithObjects:cancelButton, [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil], doneButton, nil]];
self.chooseCurrencyTxtFldRef.inputAccessoryView = toolBar;
}
#pragma mark - doneTouched
- (void)cancelTouched:(UIBarButtonItem *)sender{
// hide the picker view
[self.chooseCurrencyTxtFldRef resignFirstResponder];
}
#pragma mark - doneTouched
- (void)doneTouched:(UIBarButtonItem *)sender{
// hide the picker view
[self.chooseCurrencyTxtFldRef resignFirstResponder];
// perform some action
}
#pragma mark - The Picker Challenge
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {
return 1;
}
-(NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component{
return [availableCurreniesArray count];
}
- (nullable NSString *)pickerView:(UIPickerView *)pickerView titleForRow: (NSInteger)row forComponent:(NSInteger)component{
return availableCurreniesArray[row];
}
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
self.chooseCurrencyTxtFldRef.text = availableCurreniesArray[row];
}