iPhone:How to manage UITextfield delegate methods on dynamic number of customcells - iphone

I have dynamic number of textfields in my tableview, I put each textfield into a customcell in IB and load the cells by nibName.
I want to validate and show alert as user enters data, also when editingisDone I want to get the input value from user and save it to the relavent object.
for instance these are some delegate methods I can use:
- (void)textFieldDidEndEditing:(UITextField *)textField{
//save the data
}
- (IBAction)textFieldDoneEditing:(id)sender {
//hide the keypad when done is pressed
[sender resignFirstResponder];
}
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange{}
2 questions:
1-When getting user input and validating the input how will I know which textfield's delegate is fired since there are dynamic numbers of cells and textfields, and how can I manage this?
2-For hiding the keyboard I did this but not sure this is correct;
-In IB I opened the customcell-->right click uitextfield and connect its didEndonExit to FirstResponder's textFieldDoneEditing method. This works but I can't return if I didnt add any chars to textfield. so it forces to write something in order to press the button.

With regards to your first question ...
In the following code I'll assume you have one UITextField in each cell. I'll also assume you've created an UITableViewCell subclass called CustomCell which contains an UITextField.
#pragma mark - UITableViewDataSource
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"CellIdentifier";
CustomCell *cell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell)
{
cell = [[[CustomCell alloc] initWithStyle:UITableViewCellStyleDefault identifier:CellIdentifier] autorelease];
cell.textField.tag = indexPath.row;
cell.textField.delegate = self;
}
return cell;
}
#pragma mark - UITextFieldDelegate
- (void)textFieldDidEndEditing:(UITextField *)textField
{
NSLog(#"textField tag: %d", textField.tag); // this will show which textField did end editing ...
}

Regarding your second question; if I understand your problem correctly, unchecking "Auto-enable Return Key" in the textfield's properties in IB should allow you to press the return button even when it's empty. I tested this on a simple textfield in a UIView, but it should work in your case.

Related

Remove all UITextView's Gesture Recognizers

I am developing an app that has a UITextView within a custom UITableViewCell in a tableview. The tableviewcell has several gesture recognizers. My problem is that the textview is responding to touches before the tableViewCell's recognizers. I have a long tap for moving the cell to another location but instead the textview will try and select it's text for copy/paste/magnifying glass functions. Also, the textview is swallowing touches from the tableview itself and so scrolling will not function within the tableview if you begin the scroll touching the textview.
even with the editable property set to false the textview still wants to select text and show the magnifying glass.
Initially I had everything working using a UITextField instead of a UITextView but I need support for multiple lines of text.
So how can I keep the textview from swallowing any touch event? Any suggestions or thoughts would be greatly appreciated.
Here's how we handle UITextView user interaction that is contained within a UITableViewCell:
1) Your UIViewController should conform to UITableViewDataSource, UITableViewDelegate and UITextViewDelegate :
#import <UIKit/UIKit.h>
#interace MyExampleController : UIViewController <UITableViewDataSource, UITableViewDelegate, UITextViewDelegate>
2) Initially, the text view's userInteractionEnabled property is set to NO
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *textViewCellIdentifier = #"MyTextViewCellIdentifier";
MyTextViewViewCell *cell = [tableView dequeueReusableCellWithIdentifier:textViewCellIdentifier];
if (!cell)
{
// ... do your stuff to create the cell...
cell.textView.userInteractionEnabled = NO;
cell.textView.delegate = self;
}
// do whatever else to set the cell text, etc you need...
return cell;
}
3) Check if a text view cell was tapped via UITableViewDelegate method:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
BOOL isTextViewCell = ... // do your check here to determine if this cell has a text view
if (isTextViewCell)
{
[[(MyTextTableViewCell *)cell textView] setUserInteractionEnabled:YES];
[[(MyTextTableViewCell *)cell textView] becomeFirstResponder];
}
else
{
// ... do whatever else you do...
}
}
4) Check for \n to determine when to have the textView resign first responder (passed when user presses the return key):
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
if ([text rangeOfString:#"\n"].location != NSNotFound)
{
[textView resignFirstResponder];
textView.
return NO;
}
return YES;
}
5) Save text into your model once after the text view has resigned (ends editing):
- (void)textViewDidEndEditing:(UITextView *)textView
{
NSString *text = textView.text;
// do your saving here
}
This was mostly written on the spot, so there may be some minor errors in there, but hopefully you get the general idea.
Good luck.

How to access values entered in a UITableViewCell?

I have a prototype table in my app witch I populate with a customTableViewCell class with a UITextField inside.
In my navigation bar I got a save button.
The question is, how to access this dynamic created cell's to get the UITextField content?
This is my code, you can see that I tried to use NSMutableArray
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"customTableCell";
customTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
[self.pfCells addObject:cell];
if(cell == nil)
{
cell = [[customTableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
}
// Configuration
cell.lblName.text = [self.pfFields objectAtIndex: [indexPath row]];
cell.txtType = [self.pfTypes objectAtIndex: [indexPath row]];
if ([[self.pfTypes objectAtIndex:[indexPath row]] isEqualToString: #"n"]) {
[cell.txtField setKeyboardType:UIKeyboardTypeNumberPad];
} else if ([[self.pfTypes objectAtIndex:[indexPath row]] isEqualToString: #"m"]) {
[cell.txtField setKeyboardType:UIKeyboardTypeEmailAddress];
}
return cell;
}
Here's another way to save content from a UITextField contained in a UITableViewCell:
Inside tableView:cellForRowAtIndexPath: set the delegate and a tag for txtField
Implement textFieldDidEndEditing: check for a UITextField tag value an save data in a private variable
Reload UITableView
The biggest advantage of this implementation if the fact that you doesn't need to iterate over whole tableview everytime you change a textfield value.
Quick answer:
#pragma mark - UITextFieldDelegate
- (void)textFieldDidEndEditing:(UITextField *)textField
{
// grab the row we are working on
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
// remove the old key/value pair if it exists and add the new one
[self.modelDictionary removeObjectForKey:indexPath];
[self.modelDictionary setObject:textField.text forKey:indexPath];
}
Be sure to add cell.txtField.delegate = self when configuring your cell. Then in your save button, you'd iterate through the dictionary and save the values -- or just save the dictionary itself.
Also, if you are targeting iOS6 or later, use dequeueReusableCellWithIdentifier:forIndexPath: as this method guarantees a cell is returned and resized properly, so you don't have to check for nil and manually init your cell.
Longer answer:
You generally never want to store your model in your view as you are doing. Aside from it breaking the MVC design patterns, it also causes issues with UITableViews. Specifically, a UITableViewCell will be recycled when it scrolls off the screen. So any values you have in those fields are lost. While you can get away with doing this if you only have visible rows that never scroll off the screen, I would encourage you to avoid this approach altogether.
Instead, you should store the values entered into the textboxes in your model object. The easiest way to do this is to use UITextFieldDelegate's textFieldDidEndEditing: to grab the values after the user enters them, then add these values to your model. You model could be something as simple as an NSDictionary using the indexPath as the key.

Table cell as the delegate of the text field inside it?

I unfortunately still have not seen the light when it comes to organising my iphone app nicely into controllers and views. Let me illustrate with an example:
I am working on a sign up page which consists of a table view with a list of custom table cells. Some of these cells have a text field inside them and when the user touches one of those a keyboard slides up from the bottom. The keyboard has a return key in its lower right corner and when the user hits this key I would like the keyboard to slide down again.
Now, where do I put the
- (BOOL) textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];
return YES;
}
? Currently I have made my custom table cell conform to the text field delegate protocol and have put the method in there, but it does seem a bit wrong to have stuff like that inside a view class? On the other hand I do not find it appropriate in the table view controller either.
you can set your table view controller as the text field's delegate...
just remove the code in the custom cell where you set it as the delegate and instead set the delegate in the table view controller's cellForRowAtIndexPath method where you actually create and return the cell..
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"CellIdentifier";
MyCustomCell *myCell = (MyCustomCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (myCell == nil)
{
myCell = [[[MyCustomCell alloc] initWithStyle:UITableViewCellSelectionStyleNone reuseIdentifier:CellIdentifier] autorelease];
myCell.myTextField.delegate = self;
}
//other cell specific code goes here
return myCell;
}

UITextField in UITableViewCell Help

I have scoured the internet looking for a good tutorial or posting about having a UITableView populated with a UITextField in each cell for data entry.
I want to keep track of each UITextField and the text written within it while scrolling. The tableView will be sectioned. I have been using a custom UITableViewCell but I'm open to any method.
Also, is it possible to use the textFields as ivars?
If any of you could point me in the right direction, it would be greatly appreciated.
Thank you in advance!
To solve your problem you have to maintain an array, with some number (number of textFields you added to all cells) of objects.
While creating that array you need add empty NSString objects to that array. And each time while loading the cell you have to replace the respected object to respected textField.
Check the following code.
- (void)viewDidLoad{
textFieldValuesArray = [[NSMutableArray alloc]init];
for(int i=0; i<numberofRows*numberofSections; i++){
[textFieldValuesArray addObject:#""];
}
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Return the number of sections.
return numberofSections;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return numberofRows;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
CustomTextField *tf = [[CustomTextField alloc] initWithFrame:CGRectMake(5,5,290,34)];
tf.tag = 1;
[cell.contentView addSubView:tf];
[tf release];
}
CustomTextField *tf = (CustomTextField*)[cell viewWithTag:1];
tf.index = numberofSections*indexPath.section+indexPath.row;
tf.text = [textFieldValuesArray objectAtIndex:tf.index];
return cell;
}
- (void)textFieldDidEndEditing:(UITextField *)textField{
int index = textField.index;
[textFieldValuesArray replaceObjectAtIndex:index withObject:textField.text];
}
First of all, you must understand that UITableViewCell and UITextField are just views, they are not supposed to hold data, they are just supposed to display them and allow the user to interact with them: The data should remain stored in the controller of the table view.
You have to remember that UITableView allows you to reuse UITableViewCell instances for performance purpose: what's displayed on the screen are actually the only subviews UITableView keep there. It means that you'll reuse one cell that already has a text field in it and set the text on that field directly. When the user will tap on the field it will edit it and you'll have to get the value back from it when the user will have finished.
The fastest way, would be to use what Satya proposes, that is building normal UITableViewCell and insert into a UITextField (there's no need for a CustomTextField class...). The tag will allow you to get back to the text field easily... But you'll have to setup your text field so it behaves properly when the table view resizes or if a label in the same cell changes.
The cleanest way to do that is to subclass UITableViewCell and setup the layout of your label and text field, and you can provide the text field as a property of the custom subclass.
I have used Textfields in tableview for data entry.
I have customised the UITextField class in a separate class called Utility :
In Utility.h
#interface CustomUITextField:UITextField{
NSInteger rowNumber;
}
In Utility.m
#implementation CustomUITextField
#synthesize rowNumber;
#end
My tableView cellForRowAtIndexPath method is
- (UITableViewCell *)tableView:(UITableView *)theTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *Identifier = #"Cell";
UITableViewCell *cell = [theTableView dequeueReusableCellWithIdentifier:Identifier];
if(cell == nil)
cell = [self reuseTableViewCellWithIdentifier:Identifier withIndexPath:indexPath];
CustomUITextField *itemNameTextField = (CustomUITextField *)[cell.contentView viewWithTag:TEXTFIELD_TAG];//this is the tag I have set in reuseTableViewCellWithIdentifier method for textfield
itemNameTextField.rowNumber = indexPath.row;
itemNameTextField.text = #"";//you can set it for the value you want
if(itemListTable.editing)
itemNameTextField.borderStyle = UITextBorderStyleRoundedRect;
else
itemNameTextField.borderStyle = UITextBorderStyleNone;
return cell;
}
You can customise the delegate methods of UITextField for CustomUITextField & can save the text entered in a particular row's textfield by accessing the CustomTextField's row number.
Just try with this.
I had the same problem here is some code i found that treats this problem . it puts the data enterd in a Array Look at the Debugger console to see the results of the text being typed here's the link TextFieldCell. . Happy Codeing

Accessing UITextField in a custom UITableViewCell

I have a UITableViewCell (with associated UITableViewCell sub class, .m & .h) created in IB which contains a UITextField. This UITextField is connected up to an IBOutlet in the UITableViewCell sub class and also has a property. In my table view controller I am using this custom cell with the following code:
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"textfieldTableCell"];
if (cell == nil) {
// Create a temporary UIViewController to instantiate the custom cell.
UIViewController *temporaryController = [[UIViewController alloc] initWithNibName:#"TextfieldTableCell" bundle:nil];
// Grab a pointer to the custom cell.
cell = (TextfieldTableCell *)temporaryController.view;
// Release the temporary UIViewController.
[temporaryController release];
}
return cell;
}
The UITextField displays fine and the keyboard pops up when clicked as expected, but how do I access (get .text property) the UITextField that each row contains? and also how do I handle the 'textFieldShouldReturn' method of the UITextFields?
I think what the OP is trying to understand is how to access the UITextField value once the user has entered data into each fields. This will not be available at the time the cells are created as suggested by #willcodejavaforfood.
I've been implementing a form and trying to make it as user friendly as possible. It is doable but be aware that it can get quite convoluted depending on the number of UITableViewCells / UITextFields you have.
Firstly to your question re: accessing the values of UITextField:
1) Make your view controller a <UITextFieldDelegate>
2) Implement the following method:
- (void) textFieldDidEndEditing:(UITextField *)textField {
NSIndexPath *indexPath = [self.tableView indexPathForCell:(CustomCell*)[[textField superview] superview]]; // this should return you your current indexPath
// From here on you can (switch) your indexPath.section or indexPath.row
// as appropriate to get the textValue and assign it to a variable, for instance:
if (indexPath.section == kMandatorySection) {
if (indexPath.row == kEmailField) self.emailFieldValue = textField.text;
if (indexPath.row == kPasswordField) self.passwordFieldValue = textField.text;
if (indexPath.row == kPasswordConfirmField) self.passwordConfirmFieldValue = textField.text;
}
else if (indexPath.section == kOptionalSection) {
if (indexPath.row == kFirstNameField) self.firstNameFieldValue = textField.text;
if (indexPath.row == kLastNameField) self.lastNameFieldValue = textField.text;
if (indexPath.row == kPostcodeField) self.postcodeFieldValue = textField.text;
}
}
I also use a similar syntax to make sure the current edited field is visible:
- (void) textFieldDidBeginEditing:(UITextField *)textField {
CustomCell *cell = (CustomCell*) [[textField superview] superview];
[self.tableView scrollToRowAtIndexPath:[self.tableView indexPathForCell:cell] atScrollPosition:UITableViewScrollPositionMiddle animated:YES];
}
And finally, you can handle textViewShouldReturn: in a similar way:
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
NSIndexPath *indexPath = [self.tableView indexPathForCell:(CustomCell*)[[textField superview] superview]];
switch (indexPath.section) {
case kMandatorySection:
{
// I am testing to see if this is NOT the last field of my first section
// If not, find the next UITextField and make it firstResponder if the user
// presses ENTER on the keyboard
if (indexPath.row < kPasswordConfirmField) {
NSIndexPath *sibling = [NSIndexPath indexPathForRow:indexPath.row+1 inSection:indexPath.section];
CustomCell *cell = (CustomCell*)[self.tableView cellForRowAtIndexPath:sibling];
[cell.cellTextField becomeFirstResponder];
} else {
// In case this is my last section row, when the user presses ENTER,
// I move the focus to the first row in next section
NSIndexPath *sibling = [NSIndexPath indexPathForRow:kFirstNameField inSection:kOptionalSection];
MemberLoginCell *cell = (MemberLoginCell*)[self.memberTableView cellForRowAtIndexPath:sibling];
[cell.cellTextField becomeFirstResponder];
}
break;
}
...
}
In cellForRowAtIndexPath: include this code,
yourTextField.tag=indexPath.row+1; //(tag must be a non zero number)
Then access the textField using
UITextField *tf=(UITextField *)[yourView viewWithTag:tag];
There is even more simpler way to solve both problems,
1.Create a custom uitableviewCell class for the cell, (e.g.textfieldcell)
2.Now, in the textfieldcell.h file call textFieldDelegate
3.In the textfieldcell.m file write textFieldDelegate methods
ie
-(BOOL)textFieldShouldReturn:(UITextField *)textField;
-(void)textFieldDidEndEditing:(UITextField *)textField;
(first problem)Now, in
-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
[self.mytextBox resignFirstResponder];
return YES;
}
5.(second problem),
-(void)textFieldDidEndEditing:(UITextField *)textField
{
nameTextField = mytextBox.text;
}
6.create a custom delegate method in the MaintableViewController
#protocol textFieldDelegate <NSObject>
-(void)textName:(NSString *)name;
#end
7.In MaintableViewController.m file write the implementation of the delegate method,
-(void)textName:(NSString *)name{
Nametext = name;
NSLog(#"name = %#",name);
}
8.call the delegate method in the cell class , and pass the variable in the didendmethod
9.now, assign self to cell.delegate ,when initializing the cell in uitableview
10.thats it you got the variable passed from textfield to the main view, Now do whatever u want with the variable
This is how I managed to get the text inside the UITextField inside my custom UITableViewCell in Swift. I accessed this inside my UIButton inside another custom UITableViewCell that has an #IBAction on my UITableViewController. I only have one section in my UITableViewController but that doesn't matter anyway because you can easily set and assign this yourself.
#IBAction func submitButtonTapped(sender: UIButton) {
print("Submit button tapped")
let usernameCell = self.tableView.cellForRowAtIndexPath(NSIndexPath(forRow: 0, inSection: 0)) as! UsernameTableViewCell
print("Username: \(usernameCell.usernameTextField.text)")
}
Whenever I tapped my UIButton, it gives me the updated value of the text inside my UITextField.
If you have created a class for your custom cell I'd advise you to work against it.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
MyCustomCell* cell = (MyCustomCell *) [tableView dequeueReusableCellWithIdentifier:#"BDCustomCell"];
if (cell == nil) {
// Load the top-level objects from the custom cell XIB.
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"MyCustomCell" owner:self options:nil];
// Grab a pointer to the first object (presumably the custom cell, as that's all the XIB should contain).
cell = (MyCustomCell *) [topLevelObjects objectAtIndex:0];
}
// This is where you can access the properties of your custom class
cell.myCustomLabel.text = #"customText";
return cell;
}
This tutorial was helpful to me. You can reference whatever object you need through the tag.
In the Storyboard drag on a UIImageView or UITextField etc. and set the tag to 100 (whatever you want) then in your - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath use the tag to reference it.
Here's something you could do, just remember to set the tags in the storyboard:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// Configure the cell...
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
UITextField *tField = (UITextField *)[cell viewWithTag:100];
return cell;
}