UIPickerview Multiple TextFields Xcode - iphone

I'm looking for a way to use a single UIPickerview for two different textfields. I'd like to have the pickerview popup when each textfield is selected. After the user selects their item, the item will populate the specific text field. The picker would have to populate based on the textfield chosen.
I've read this:
How to use one UIPickerView for multiple textfields in one view?
and this:
How to use UIPickerView to populate different textfields in one view?
and this:
Multiple sources for UIPickerView on textfield editing
However, none gives a complete solution.
I'm very new at Xcode so I'd like a solution that includes steps to set the storyboard also.
I appreciate any help as i've researched this for weeks.
EDIT: HERE IS MY CODE:
.h:
#import <UIKit/UIKit.h>
#interface klViewController : UIViewController <UIPickerViewDelegate, UIPickerViewDataSource> {
IBOutlet UITextField *textField1;
IBOutlet UITextField *textField2;
NSMutableArray *pickerArray1;
NSMutableArray *pickerArray2;
UIPickerView *pickerView;
}
#property(nonatomic,retain) IBOutlet UITextField *textField1;
#property(nonatomic,retain) IBOutlet UITextField *textField2;
#property(nonatomic,retain) IBOutlet UIPickerView *pickerView;
#end
.m:
#import "klViewController.h"
#interface klViewController ()
#end
#implementation klViewController
#synthesize pickerView;
#synthesize textField1;
#synthesize textField2;
int variabla;
-(void)textFieldDidBeginEditing:(UITextField *)textField{
[pickerView setHidden:YES];
if (textField1.editing == YES) {
[textField1 resignFirstResponder];
[pickerView setHidden:NO];
variabla = 1;
}else if (textField2.editing == YES) {
[textField2 resignFirstResponder];
[pickerView setHidden:NO];
variabla = 2;
}
NSLog(#"variabla %d",variabla);
[pickerView reloadAllComponents];
}
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView;
{
return 1;
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component;
{
if (variabla == 1) {
return [pickerArray1 count];
}else if (variabla == 2) {
return [pickerArray2 count];
}else {
return 0;
}
}
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component;
{
if (variabla == 1) {
return [pickerArray1 objectAtIndex:row];
}else if (variabla == 2) {
return [pickerArray2 objectAtIndex:row];
}else {
return 0;
}
}
- (void)textFieldShouldReturn:(UITextField *)textField{
[textField resignFirstResponder];
}
- (void)viewDidLoad {
[super viewDidLoad];
[pickerView setHidden:YES];
pickerArray1 = [[NSMutableArray alloc] initWithObjects:#"0", #"1", #"2", nil];
pickerArray2 = [[NSMutableArray alloc] initWithObjects:#"3", #"4", #"5", nil];
}
#end
HERE IS A SCREEN SHOT OF MY STORYBOARD:
STATUS UPDATE:
When I run the program:
1) the pickerview is hidden.
2) when I select a textfield, the picker view appears and populates correctly depending on the textfield selected.
PROBLEMS:
1) Picker doesn't go away when click outside of the textfield.
2) Textfields don't populated when a row in the Picker is selected.
Hope this provides more insight.

1) Picker doesn't go away when click outside of the textfield.
You have no code that attempts to make the picker go away when that happens. Try adding a simple tap gesture recognizer to the view. Add a line to viewDidLoad like:
[self.view addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(backgroundTap:)]];
Then implement the function simply like:
-(void)backgroundTap:(UITapGestureRecognizer *)tapGR{
self.pickerView.hidden = YES;
// And maybe..
variabla = 0;
}
Since you are making the picker appear and disappear using the hidden property this will work very simply. There are other more sophisticated ways to do this which I hope you explore. Generally the picker is set as the textfield's inputView property; that is worth investigating.
2) Textfields don't populated when a row in the Picker is selected.
You haven't handled the picker's pickerView:didSelectRow:inComponent: delegate method. That's the method that gets called when the picker stops turning and lands on an item. Don't assume that this is the item the user selected it will be called multiple times.
-(void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component{
NSString *text = [self pickerView:pickerView titleForRow:row forComponent:component];
UITextField *current = nil;
if (variabla == 1) current = self.textField1;
else if (variabla == 2) current = self.textField2;
current.text = text;
}
That should get your implementation working. One more thing though variabla is an instance variable and should be declared in curly braces immediately following the #interface or #implementation line.
#implementation klViewController {
int variabla;
}
#synt....

Give the Tag of two Different textfield for identify which textfield you select and everything is ok you just need to change below method.
Hope This Work
-(void)textFieldDidBeginEditing:(UITextField *)textField {
if ([textField viewWithTag:100]) {
[textField resignFirstResponder];
[self.View1 setHidden:NO];
variable=1;
}
else if ([textField viewWithTag:101]) {
[textField resignFirstResponder];
[self.View1 setHidden:NO];
variable=2;
}
[_Picker_view reloadAllComponents];
}
Thanks :)

Make sure you have declared the Picker View object in the header file.
In the header file, import the UITextFieldDelegate protocol:
#interface MyView:UIViewController < UITextFieldDelegate>
In IB, set a tag for each text field you have.
In the *.m file, implement the textFieldShouldBeginEditing method, update the PickerView array Data Source and Reload all the picker view components.
-(BOOL) textFieldShouldBeginEditing:(UITextField *)textField {
if (textField.tag == 1) {
itemsArray = [[NSArray alloc] arrayWithObjects:#"A", #"B"];
}
if (textField.tag == 2) {
itemsArray = [[NSArray alloc] arrayWithObjects:#"Green", #"Yellow"];
}
[myPickerView reloadAllComponents];
}
Make sure you import the UIPickerViewDelegate and UIPickerViewDataSource in the header file.
You can use the same picker view for as many text fields as you want, to change the content of the picker view according to the selected text field you need to replace the data source of the picker view with different items whenever a text field is being selected and then reload the picker view components.
Well my friend, I'm afraid it's a little bit to complicated to explain here.
You can set object's tag value in the IB properties menu.
Once you dragged a PickerView into your view and it's selected, you can change the tag attribute in the Object Properties menu (on the side).
I think you should look for tutorials that will show you how to setup a simple picker view, or table view (they work very similar to one another) and that will give you much more information on how to do what you want to do. In a nutshell, every Picker View takes information from a Data Source, you can create an array that contains some strings and have the picker view load each item in the array as a row. I have a small website with some beginners information, check it out.
http://i-tutor.weebly.com/index.html

In .h
#interface TQViewController : UIViewController<UIPickerViewDelegate>
{
UITextField *textfield;
UIPickerView *Picker1;
NSArray *Array1,*Array2;
}
end
and in .m
- (void)viewDidLoad
{
[super viewDidLoad];
//TextField
textfield=[[UITextField alloc]initWithFrame:CGRectMake(5,5,310,40)];
textfield.borderStyle = UITextBorderStyleRoundedRect;
textfield.backgroundColor=[UIColor whiteColor];
textfield.textAlignment = UITextAlignmentCenter;
textfield.placeholder = #"<enter amount>";
[self.view addSubview:textfield];
textfield1=[[UITextField alloc]initWithFrame:CGRectMake(5,100,310,40)];
textfield1.borderStyle = UITextBorderStyleRoundedRect;
textfield1.backgroundColor=[UIColor whiteColor];
textfield1.textAlignment = UITextAlignmentCenter;
textfield1.placeholder = #"<enter amount>";
[self.view addSubview:textfield1];
// PickerView1
Array1=[[NSArray alloc]initWithObjects:#"USD",#"INR",#"EUR", nil];
Picker1=[[UIPickerView alloc]initWithFrame:CGRectMake(0, 50, 320,10)];
Picker1.delegate=self;
Picker1.tag=PICKER1_TAG;
Picker1.showsSelectionIndicator=YES;
[self.view addSubview:Picker1];
Array2=[[NSArray alloc]initWithObjects:#"USD",#"INR",#"EUR", nil];
}
-(NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
if([textfield becomeFirstResponder])
return [Array1 count];
if([textfield1 becomeFirstResponder])
return [Array2 count];
}
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {
NSString *title;
if([textfield becomeFirstResponder])
{
title=[Array1 objectAtIndex:row];
return title;
}
([textfield1 becomeFirstResponder])
{
title=[Array2 objectAtIndex:row];
return title;
}
}
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
if([textfield becomeFirstResponder])
{
//your code
}
([textfield1 becomeFirstResponder])
{
//your code
}
}

Related

How do I add rows to UIPickerView from UIAlertController

I have a UIPickerView that gets its data from an array that is defined in
friends = [NSArray arrayWithObjects: #"jim", #"joe", #"anne", nil];
I have a button under the picker that is supposed to add new friends to the picker.
When the button is pressed a UIAlertController pops up and the user can enter the new friends name. I can save the text as a string but I can't add it to the array. I've also tried using NSMutableArray's.
I'm new to this so all input would be great. I've looked at similar questions for help but nothing has worked.
Thanks!
Ok so I will try to explain this:
You declare a NSMutbleArray, you can't expect to use a NSArray because is not mutable, and you need to modify the content.
NSMutableArray *array;
UIAlertController * view;
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSArray* friends = [NSArray arrayWithObjects: #"jim", #"joe", #"anne", nil];
array = [NSMutableArray arrayWithArray:friends];
// I added a UIPickerView in the StoryBoard, connected it to a property and the delegates and datasources.
self.pickerView.delegate = self;
}
Then you declare dataSource of UIPickerView:
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView{
return 1;
}
// returns the # of rows in each component..
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component{
return array.count;
}
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component{
return array[row];
}
So, then you present your UIAlertController, in this case I will dismiss it in the Return of the TextView.
//This is an action connected to the button which will present the ActionController
- (IBAction)addFriend:(id)sender {
view = [UIAlertController alertControllerWithTitle:#"Add Friend" message:#"Write the friend to add"preferredStyle:UIAlertControllerStyleAlert];
[view addTextFieldWithConfigurationHandler:^(UITextField *textField) {
textField.placeholder = #"Friend";
textField.delegate = self;
textField.tag = 01;
}];
[self presentViewController:view animated:YES completion:nil];
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField{
if(textField.tag == 01){
[array insertObject:textField.text atIndex:array.count];
[view dismissViewControllerAnimated:YES completion:^{
[self.pickerView reloadAllComponents];
}];
return YES;
}
return YES;
}
This is more or less what you can do, I was the most specific I could be because you said you are a begginer.
Hope it Helps.

Trouble with the UITextField inputview property pulling up a custom UIPickerView

I have been having trouble pulling up a custom UIPickerView from the textfield's inputview property. I have been working on this for awhile, did some research, and tried to put together a separate project based on Apple's UICatalog example.
However, whenever I tap inside the textfield all I get is a black screen that pops up in place of the picker view. Im sure I've overlooked something but I have been looking for days any help would be appreciated.
Keep in mind this was my test project to see if I could add this functionality to my other app and that a lot of the code I tried to copy from the UICatalog app. Sorry if anything doesn't make sense and please feel free to ask any questions you may have. Thank you.
// ViewController.h
// TestPicker
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController<UITextFieldDelegate,UIPickerViewDelegate,UIPickerViewDataSource>{
UIPickerView *picker;
//The picker view the textfield responds to.
IBOutlet UITextField *myText;
//The textfield which has the input view of a picker.
NSArray *testArray;
//The array which values are loaded into the picker.
}
#end
// ViewController.m
// TestPicker
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad
{
picker.delegate=self;
picker.dataSource=self;
myText.delegate=self;
[self createPicker];
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)viewDidUnload
{
myText = nil;
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
else {
return YES;
}
}
-(BOOL)textFieldShouldBeginEditing:(UITextField *)textField{
picker = [[UIPickerView alloc] initWithFrame:CGRectZero];
myText.inputView=picker;
return YES;
}
-(void)textFieldDidBeginEditing:(UITextField *)textField{
}
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
NSString *returnStr = #"";
if (pickerView == picker)
{
if (component == 0)
{
returnStr = [testArray objectAtIndex:row];
}
else
{
returnStr = [[NSNumber numberWithInt:row] stringValue];
}
}
return returnStr;
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
return [testArray count];
}
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
return 1;
}
- (void)createPicker
{
testArray = [NSArray arrayWithObjects:
#"John Appleseed", #"Chris Armstrong", #"Serena Auroux",
#"Susan Bean", #"Luis Becerra", #"Kate Bell", #"Alain Briere",
nil];
picker = [[UIPickerView alloc] initWithFrame:CGRectZero];
picker.showsSelectionIndicator = YES; // note this is default to NO
picker.delegate = self;
picker.dataSource = self;
}
#end
The problem is in this method:
-(BOOL)textFieldShouldBeginEditing:(UITextField *)textField{
picker = [[UIPickerView alloc] initWithFrame:CGRectZero];
myText.inputView=picker;
return YES;
}
You already created picker in your createPicker method, called from viewDidLoad, so this creates another instance (this instance won't have the delegate or data source set to self, since these were set on the first instance you created). If you just delete the first line of this method, it should work.
Two other comments on your code. The first 2 lines in the viewDidLoad method aren't doing anything since you haven't created picker yet -- they should be deleted. You also need to implement the pickerView:didSelectRow:inComponent: method in order to get the selected value of your picker into the text field.

UIPickerView and UITextField get value from UIPickerView

Ok I am having trouble figuring out how to approach this.
I have a UITextField which I add to a UITableView dynamically according to the definitions of a XML file, in the XML file I may specify a list as one of the data types and what I do then is add a UIPickerView that displays the list to the inputView of my specific UITextField.
What I am having trouble with is figuring out how to take the selected value from the UIPickerView and add it to the text property of my UITextField
My UIPickerView is a custom class but I added no extra functionality I only overrode it to make it possible to pass a datasource to the UIPickerView as a property.
Here is my PickerViewDataSourceAndDelegate.h
#import <Foundation/Foundation.h>
#interface PickerViewDataSourceAndDelegate : UIPickerView <UIPickerViewDelegate, UIPickerViewDataSource>
#property (nonatomic, strong) NSMutableArray *pickerData;
#end
And it's .m file
#import "PickerViewDataSourceAndDelegate.h"
#implementation PickerViewDataSourceAndDelegate
#synthesize pickerData;
-(id)init {
if (self = [super init])
{
self.pickerData = [[NSMutableArray alloc] init];
}
return self;
}
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)thePickerView {
return 1;
}
- (NSInteger)pickerView:(UIPickerView *)thePickerView numberOfRowsInComponent:(NSInteger)component {
return [self.pickerData count];
}
- (NSString *)pickerView:(UIPickerView *)thePickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {
return [self.pickerData objectAtIndex:row];
}
#end
This is how I add the UITextField with the UIPickerView as inputView
for(NodeProperty *nodeproperty in node.properties)
{
if(nodeproperty.flowDirection == (FlowDirection*)Output)
{
if([nodeproperty.typeName isEqualToString:#"System.String"] && nodeproperty.extendedType == (ExtendedType*)None && [nodeproperty.enumValues count] == 0)
{
...
}
else if([nodeproperty.typeName isEqualToString:#"System.String"] && nodeproperty.extendedType == (ExtendedType*)MultilineText && [nodeproperty.enumValues count] == 0)
{
...
}
else if([nodeproperty.typeName isEqualToString:#"System.Boolean"] && nodeproperty.extendedType == (ExtendedType*)None && [nodeproperty.enumValues count] == 0)
{
...
}
else if([nodeproperty.typeName isEqualToString:#"System.Double"] && nodeproperty.extendedType == (ExtendedType*)None && [nodeproperty.enumValues count] == 0)
{
...
}
else if([nodeproperty.typeName isEqualToString:#"System.String"] && nodeproperty.extendedType == (ExtendedType*)None && [nodeproperty.enumValues count] > 0)
{
UILabel *fieldLabel = [[UILabel alloc] initWithFrame:CGRectMake(5, 5, 290, 20)];
fieldLabel.text = nodeproperty.name;
[rowsInSectionLabels addObject:fieldLabel];
PickerViewDataSourceAndDelegate *pickerDataDel = [[PickerViewDataSourceAndDelegate alloc] init];
pickerDataDel.pickerData = nodeproperty.enumValues;
pickerDataDel.dataSource = pickerDataDel;
pickerDataDel.delegate = pickerDataDel;
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(5, 25, 290, 30)];
[textField setBorderStyle:UITextBorderStyleRoundedRect];
textField.inputView = pickerDataDel;
[rowsInSection addObject:textField];
}
else
{
....
For space I omitted some of the space, if some things are unclear I will gladly explain.
Every thing works perfectly with no exceptions, I just want to get the selected value out of the picker
See the picker view delegate protocol. Implement this method:
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
In here, you can get the appropriate value from the model and update your text field.
To work out which is the current text field, you'd need to find out which of the text fields is the first responder.
Have all of the text fields in an IBOutletCollection or array, iterate through them and find the one which is first responder.
Or, if you have text field delegates, you can set an ivar for the current text field in the didBeginEditing delegate method, and use this in the picker view delegate method above.
I found my own solution that words like a charm, I had to create a delegate method to pass the value back to my UITextField.
First I declared a protocol in my PickerViewDataSourceAndDelegate.h
#protocol PickerRowSelected
-(void) selectedARowAndValueIs:(NSString*)aValue;
#end
Then I added a member:
id <PickerRowSelected> adelegate;
and added a property
#property (nonatomic, strong) id<PickerRowSelected> adelegate;
I then added this function
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
[adelegate selectedARowAndValueIs:[self.pickerData objectAtIndex:row]];
}
And in the controller that contains the textfield I added:
pickerDataDel.adelegate = self;
And implemented my new delegate method
-(void) selectedARowAndValueIs:(NSString *)aValue
{
UITextField *aview = (UITextField*)[self.view findViewThatIsFirstResponder];
aview.text = aValue;
}
See my answer on this question for finding the view that is the first responder
Find View that is the firstresponder
Use -[UIPickerView selectedRowInComponent:] to determine which row is selected, and then return the object at that index within your data array.
- (void)pickerView:(UIPickerView *)pickerView1 didSelectRow: (NSInteger)row inComponent:(NSInteger)component {
NSInteger selectedRow = [pickerView1 selectedRowInComponent:0];
NSString *selectedPickerRow=[yourArrayOfElements objectAtIndex:selectedRow];
// Handle the selection
}
Pass the String to the Text Field

UIpickerView populating multiple uitextFields in the same ScrollView

Hi I am developing an iphone app where I have populated a uipickerview and it works great with one uitextfield. But I have 6 uitextfield I need to populate and I am using the same uipickerview for each UItextfield.
I have working the Ipickerview loaded with array objects and it pops up when each field is touched. The problem is with the code below the UItextfields share the same data from the picker.
I can not figure out how to code so each field gets it own data from the UIPickerView row.
What Am I doing wrong? Any coding suggestions?
Thanks
#implementation BestViewController
-(NSInteger)numberOfComponentsInPickerView: (UIPickerView *)thePickerView
{ return 1; }
-(NSInteger)pickerView:(UIPickerView *)thePickerView numberOfRowsInComponent: (NSInteger)component
{return [list count]; }
-(NSString *)pickerView:(UIPickerView *)thePickerview titleForRow:(NSInteger)row forComponent:(NSInteger)component
{return [list objectAtIndex:row]; }
-(void)pickerView:(UIPickerView *)thePickerview didSelectRow:(NSInteger)row inComponent: (NSInteger)component
{
uitextfield1.text = [list objectAtIndex:row];
utitextfield2.text = [list objectAtIndex:row];
}
- (void)viewDidLoad {
[super viewDidLoad];
uitextfield1.inputView = pickerView;
uitextfield2.inputView = pickerView;
list = [[NSMutableArray alloc] init];
[list addObject:#"a"];
[list addObject:#"b"];
[list addObject:#"c"];
[list addObject:#"d"];
}
You need to get hold of the current first responder and set its text property rather than explicitly setting a particular text field.
So,
-(void)pickerView:(UIPickerView *)thePickerview didSelectRow:(NSInteger)row inComponent: (NSInteger)component
{
// textFields is an NSArray holding each of the textfields that are using the picker as an input view
for (UITextField textField in textFields)
{
if ([textField isFirstResponder])
{
textField.text = [list objectAtIndex:row];
break;
}
}
}
There may be a more elegant way to find the current first responder, this is off the top of my head. textFields could possibly be an IBOutletCollection, but I haven't used those myself so I can't speak with much authority.
Here is how I would do it:
First, define several different pickers. Of course you use the same UIPickerView but you change one property that helps you distinguish them. There is different data for (almost) each text field. One convenient property that Apple designed exactly for this purpose is the tag, an arbitrary integer available to every UIView. You can assign the same tags to the UITextFields.
For example:
#define kFirstTextField 101
#define kSecondTextField 102
#define kThirdTextField 103
//... etc
In the method when the text field is touched:
[myPickerView setHidden:NO]; // or however you show the picker
[myPickerView setTag:textField.tag];
[myPickerView reloadAllComponents];
In the data methods of the picker:
-(NSString *)pickerView:(UIPickerView *)thePickerview
titleForRow:(NSInteger)row
forComponent:(NSInteger)component
{
if (thePickerView.tag==kFirstTextField)
{ return [list1 count]; }
if (thePickerView.tag==kSecondTextField)
{ return [anotherOrTheSameList count]; }
// of course, you can also use a switch statement
return [defaultList count];
}
Do something similar in the titleForRow: method.
Finally, when something is picked, discriminate again by tag:
-(void) pickerView:(UIPickerView *)thePickerview
didSelectRow:(NSInteger)row
inComponent:(NSInteger)component
{
UITextField *field = (UITextField *) [thePickerview.superview viewWithTag:thePickerview.tag];
// this assumes the UIPickerView is the subview of the same view as the UITextFields
if (thePickerview.tag==kFirstTextField)
{ field.text = [list1 objectAtIndex:row]; }
if (thePickerview.tag==kSecondTextField)
{ field.text = [anotherOrTheSameList objectAtIndex:row]; }
// etc.
// alternatively:
field.text = [self pickerView:thePickerview titleForRow:row forComponent:0];
}

resignFirstResponder UITextView

I am using a UITEXTVIEW. I am trying to send a resignFirstResponder when the done button is pressed. I am not sure how to trigger the method containing the resignFirstResponder line.
I have set the UITextView's delegate to the File's Owner in Interface Builder. This is my viewcontroller's header and implementation file:
#import <Foundation/Foundation.h>
#import "Question.h"
#interface CommentQuestionViewController : UIViewController {
Question *question;
IBOutlet UILabel *questionTitle;
IBOutlet UITextView *inputAnswer; //this is the textview
}
#property (nonatomic, retain) UILabel *questionTitle;
#property (nonatomic, retain) Question *question;
#property (nonatomic, retain) UITextView *inputAnswer;
- (void) addButton:(id)sender isLast:(BOOL)last;
- (void) setQuestionId:(NSString*)quId withTitle:(NSString*)quTitle number:(NSString*)quNum section:(NSString*)sId questionType:(NSString*)qt;
#end
#import "CommentQuestionViewController.h"
#implementation CommentQuestionViewController
#synthesize questionTitle, question, inputAnswer;
- (void) addButton:(id)delegate isLast:(BOOL)last{
UIBarButtonItem *anotherButton;
anotherButton = [[UIBarButtonItem alloc] initWithTitle:#"Done" style:UIBarButtonItemStylePlain target:delegate action:#selector(finishQuestionnaire:)];
self.navigationItem.rightBarButtonItem = anotherButton;
[anotherButton release];
}
-(void)viewDidLoad{
//self.questionTitle.text = question.qTitle;
[[self questionTitle] setText:[question qTitle]];
[super viewDidLoad];
NSString *str = [NSString stringWithFormat:#"Question %#", [question qNumber]];
//self.title = str;
[self setTitle:str];
[str release];
}
-(void) setQuestionId:(NSString*)quId withTitle:(NSString*)quTitle number:(NSString*)quNum section:(NSString*)sId questionType:(NSString*)qt{
question = [[Question alloc]init];
[question setQId:quId];
[question setQTitle:quTitle];
[question setQNumber:quNum];
[question setSectionId:sId];
[question setQType:qt];
}
- (void) viewWillAppear:(BOOL)animated{
self.navigationItem.hidesBackButton = YES;
}
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void) textViewDidEndEditing:(UITextView*)textView{
[textView resignFirstResponder];
}
- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[inputAnswer release];
[questionTitle release];
[question release];
[super dealloc];
}
You can try this:
–(BOOL)textView:(UITextView*)textView shouldChangeCharactersInRange:(NSRange)range replacementText:(NSString*)text {
if ([text isEqualToString:#"\n"]) {
[textView resignFirstResponder];
return NO;
}
else
return YES;
}
Of course, you won't be able to type actual carriage returns if you do this.
After looking at your source code, the link that I had posted is pointless. I thought you were talking about the done key on the keyboard. But now I see that you were talking about an instance UIButton on the navigation bar, right?
Your addButton:isLast: method is looking great so far, but I'd change it a bit so it adheres to the Apple HIG:
- (void)addButton:(id)delegate isLast:(BOOL)last
{
UIBarButtonItem *anotherButton;
anotherButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone
target:delegate
action:#selector(finishQuestionnaire:)];
self.navigationItem.rightBarButtonItem = anotherButton;
[anotherButton release];
}
It's pretty much the same, except this one creates a button with the appropriate style.
Anyway, I don't see how the button is being added since addButton:isLast: is not being called in viewDidLoad:. Add the following line in your viewDidLoad:.
[self addButton:self isLast:NO];
last is redundant in your addButton:isLast: since it's not even being use so I just pass whatever (NO).
You're almost done, but if you press that button, your application would crash since finishQuestionnaire: is not implemented on self (CommentQuestionViewController). And since you want to dismiss the keyboard when the user presses your done button, that's where we will also resign your text view as first responder. Just add the following method:
- (void)finishQuestionnaire:(id)sender
{
[inputAnswer resignFirstResponder];
}
It's BOOL that's it..
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
if([text isEqualToString:#"\n"]) {
[textView resignFirstResponder];
return NO;
}
return YES;
}
If that doesn't work please check the following things..
Whether your textView is connected to the textView property defined in your class.. (You can see this in your xib, with an arrow icon).
2.Check whether the textView delegate is written in your .h file.
#interface YourViewController : UIViewController <UITextViewDelegate>
3.Check whether the textView's delegate is assigned.
//set this in the viewDidLoad method
self.textView.delegate = self;
Check for new line character by this method.
-(NSRange)rangeOfCharacterFromSet:(NSCharacterSet *)aSet
Then check the length of the text, if it is one character length, then new line character is entered, not pasted.
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
BOOL hasNewLineCharacterTyped = (text.length == 1) && [text rangeOfCharacterFromSet:[NSCharacterSet newlineCharacterSet]].location != NSNotFound;
if (hasNewLineCharacterTyped) {
[textView resignFirstResponder];
return NO;
}
return YES;
}