Update UITextFields from UITableViewCells without reloadind data - ios5

I have a UITableView with custom UITableViewCells , each of them has a UITextField. I assing to each textField a tag with value : indexPath.row + 100.
Well , i want to update each textField for each cell , when i type something in a specific textField. To be more clear , when I type a number, my viewcontroller should make some calculations and then assing the result to all others textFields, and this must be done each time a modify text from textField , let's say i typed 1 (make some calculations and assing result to textFields) , then i type 2 , now number to calculate from, will be 12 and so on.
The issue is that i can reloaddata from tableView without closing keyboar. System will automatically hide UIKeyboard , so reloaddata in this case does not work.
I tried to use an NSMutableArray to store all this textFields but they gets a lot , when adding them from cellForRowAtIndexPath.
How can I update properly all these UITextFields ?

It needs to update only visible cells, but not all of them.
Assuming the content calculation formula is pretty simple:
-(NSString*) textForRowAtIndex:(int)rowIndex
{
return [NSString stringWithFormat:#"%d", startRowValue + rowIndex];
}
And each cell contains UITextField object with tag indexPath.row + 100:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString* cellId = #"cellId";
UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:cellId];
if(!cell)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellId] autorelease];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
UITextField* tf = [[[UITextField alloc] initWithFrame:CGRectMake(10, 8, 280, 30)] autorelease];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(textFieldTextDidChange:)
name:UITextFieldTextDidChangeNotification object:tf];
tf.delegate = (id)self;
[cell.contentView addSubview:tf];
}
UITextField* tf = (UITextField*)[[cell.contentView subviews] lastObject];
tf.tag = indexPath.row + 100;
tf.text = [self textForRowAtIndex:indexPath.row];
return cell;
}
Then all visible cells are to be updated in textFieldTextDidChange: method:
-(void) textFieldTextDidChange:(NSNotification*)notification
{
UITextField* editedTextField = (UITextField*)[notification object];
int editedRowIndex = editedTextField.tag - 100;
int editedValue = [editedTextField.text intValue];
startRowValue = editedValue - editedRowIndex;
for (NSIndexPath* indexPath in [self.tableView indexPathsForVisibleRows])
{
if(indexPath.row != editedRowIndex)
{
UITableViewCell* cell = [self.tableView cellForRowAtIndexPath:indexPath];
UITextField* textField = (UITextField*)[cell.contentView viewWithTag:indexPath.row+100];
textField.text = [self textForRowAtIndex:indexPath.row];
}
}
}
Lets have 50 cells:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 50;
}
And lets hide keyboard when finish editing:
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
return YES;
}
Enjoy!

Related

Add subview when UITableView row is selected?

I'm working on an iPhone app that parses an XML file into a UITableView. It lists all of the titles of items within the XML file, and I'm trying to have the cell expand and add the body content of the selected item when a specified cell is selected.
I can get the cell to expand correctly, but when I have had no luck adding the body content as a subview. When populating the cell at cellForRowAtIndexPath I can add the body content and it displays fine.
My question is, how do I add a subview to the selected cell after it has been selected?
My cellForRowAtIndexPath function, with the 'functioning' bodyLabel commented out:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellID = #"Cell";
issue *curIssue = [[parser issues] objectAtIndex:indexPath.row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellID];
CGRect nameFrame = CGRectMake(0,2,300,15);
UILabel *nameLabel = [[UILabel alloc] initWithFrame:nameFrame];
nameLabel.tag = 1;
nameLabel.font = [UIFont boldSystemFontOfSize:12];
[cell.contentView addSubview:nameLabel];
CGRect bodyFrame = CGRectMake(0,16,300,60);
UILabel *bodyLabel = [[UILabel alloc] initWithFrame:bodyFrame];
bodyLabel.tag = 2;
bodyLabel.numberOfLines = 10;
bodyLabel.font = [UIFont systemFontOfSize:10];
bodyLabel.hidden = YES;
[cell.contentView addSubview:bodyLabel];
}
UILabel *nameLabel = (UILabel *)[cell.contentView viewWithTag:1];
nameLabel.text = [curIssue name];
UILabel *bodyLabel = (UILabel *)[cell.contentView viewWithTag:2];
bodyLabel.text = [curIssue body];
return cell;
}
Here is my heightForRowAtIndexPath function, where I'm trying to add the subview. When trying to execute, I receive a EXC_BAD_ACESS exception when trying to alloc the *bodyLabel element.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSInteger defCellHeight = 15;
NSInteger heightModifier = 10;
if([self cellIsSelected:indexPath]){
return defCellHeight * heightModifier;
}
return defCellHeight;
}
My didSelectRowAtIndexPath function, which allows the cell to grow/shrink:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
BOOL isSeld = ![self cellIsSelected:indexPath];
NSNumber *seldIndex = [NSNumber numberWithBool:isSeld];
[selectedIndexes setObject:seldIndex forKey:indexPath];
UILabel *label = (UILabel *)[tableView viewWithTag:2];
label.hidden = NO;
[curIssView beginUpdates];
[curIssView endUpdates];
}
And finally, the cellIsSelected helper function which returns true if the cell is selected:
-(bool) cellIsSelected:(NSIndexPath *)indexPath
{
NSNumber *selIndex = [selectedIndexes objectForKey:indexPath];
return selIndex == nil ? FALSE : [selIndex boolValue];
}
You can find the full source file here.
Seems like you're allocating and adding the same UILabel's multiple times. You should only have to do it once within the cellForRowAtIndexPath method. You might also want to set the bodyLabel to hidden in the cellForRowAtIndexPath method, then set it to not hidden when the cell has been selected. With something like:
bodyLabel.hidden = YES;
Another thing. Why are you deselecting the row within the didSelectRowAtIndexPath?
Why are you creating a UILabel in heightForRowAtIndexPath?
If you're trying to add it to the row, use the cellForRowAtIndexPath method you used above.
Simply adding a subview to the UITableViewCell or anywhere else in view with UIView's addSubview method inside of didSelectRowAtIndexPath will work for displaying a subview when a UITableView row is selected.
To add a subview to the cell when you select it, it's pretty straightforward:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
/*
.. your other setup
*/
UITableViewCell* cell = [tableView cellForRowAtIndexPath:indexPath];
[cell.contentView addSubview:<your subview>];
}

UITableView add row below selected row

I had a working tableview where I could double-tap a cell and it would add an 'action' cell below which had four buttons programmed on it.
Today I added alphabetic sections to the tableview and a section index and I can no longer get this functionality to work.
I've added a whole range of NSLogs to the code to try and find the problem and I can't, it seems to be trying to add a row in the same section and one row further down than the cell tapped, so I'm not sure what the problem is. Would anyone have any idea what I'm doing wrong?
If anyone can shed any light on this I would be hugely appreciative. (And apologies if my code is cumbersome or hard to follow, I'm new to this so feel free to suggest what I can improve!)
- (void)viewDidLoad
{
//I start with an array of objects, so I created two arrays; one containing the first letters of each Name, and a list of the number of objects that start with each of those names.
nameIndex = [[NSMutableArray alloc] init];
nameIndexCount = [[NSMutableDictionary alloc]init];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [nameIndex count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (self.actionRowIndexPath) {
//Returns first letter of the section
NSString *alphabet = [nameIndex objectAtIndex:section];
//Returns the number of entries starting with that letter
NSString *numberofRows = [nameIndexCount objectForKey:alphabet];
int intNumberOfRows = ([numberofRows integerValue] + 1);
return intNumberOfRows;
} else {
NSString *alphabet = [nameIndex objectAtIndex:section];
NSString *numberofRows = [nameIndexCount objectForKey:alphabet];
int intNumberOfRows = [numberofRows integerValue];
return intNumberOfRows;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"newTableViewCell"];
if (!cell) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"newTableViewCell"];
}
//Configure the cell
UIImageView *imageView = [[UIImageView alloc]initWithFrame:cell.frame];
UIImage *image = [UIImage imageNamed:#"LightGrey.png"];
imageView.image = image;
if ([indexPath isEqual:self.actionRowIndexPath]) {
// Four UIButtons coded programmatically
} else {
Contact *p = [[[ContactStore sharedStore]allContacts]objectAtIndex:totalNumberOfRows];
NSString *firstAndLastName = [NSString stringWithFormat:#"%# %#", [p firstName], [p lastName]];
indexPath = [self modelIndexPath:indexPath];
cell.backgroundView = imageView;
// [cell.imageView setImage:smallThumbnailImage];
[cell.imageView setImage:[p thumbnail]];
[[cell textLabel]setBackgroundColor:[UIColor clearColor]];
[[cell textLabel]setText:firstAndLastName];
[[cell detailTextLabel]setBackgroundColor:[UIColor clearColor]];
[[cell detailTextLabel]setText:[p phoneNumber]];
totalNumberOfRows = totalNumberOfRows + 1;
}
return cell;
}
#pragma mark - Action Row Support
-(NSIndexPath *)modelIndexPath: (NSIndexPath *)indexPath
{
if (self.actionRowIndexPath == nil) {
return indexPath;
}
if ([indexPath row] > [self.actionRowIndexPath row]) {
return [NSIndexPath indexPathForRow:([indexPath row] - 1) inSection:indexPath.section];
}
return indexPath;
}
- (void)handleDoubleTap:(UITapGestureRecognizer *)recognizer {
NSLog(#"Double tap");
CGPoint p = [recognizer locationInView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:p];
NSIndexPath *pathToDelete = self.actionRowIndexPath;
_selectedIndexPath = [self modelIndexPath:_selectedIndexPath];
//Is the user deselecting current row?
if (_actionRowIndexPath) {
[self.tableView deselectRowAtIndexPath:_selectedIndexPath animated:NO];
self.selectedIndexPath = nil;
self.actionRowIndexPath = nil;
} else {
//Selecting a new row
self.selectedIndexPath = indexPath;
self.actionRowIndexPath= [NSIndexPath indexPathForRow:([indexPath row] + 1) inSection:[indexPath section]];
}
[self.tableView beginUpdates];
if (pathToDelete) {
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:pathToDelete] withRowAnimation:UITableViewRowAnimationAutomatic];
}
if (self.actionRowIndexPath) {
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:self.actionRowIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}
[self.tableView endUpdates];
}
After you get the IndexPath you need to get the IndexPath.row and IndexPath.section and accordingly you need to add the object into your array at the desired index. For example: if you double tap the 2nd row in the 1st section then you need to add the object at index 4 of the array corresponding to the 1st section and then reload table. The cell would be added to the 3rd index of the 1st section.

How to insert the value in cell in tableview at particular indexpath?

I have a label and textfield in tableview, now what I want is whatever value I insert in textfield in textfieldDidEditing method it should calculate the value and return it to the label in that indexpath for tablevievw.
In textfieldDidEditing, you can get the cell of the corresponding textfield, calculate value and assign it to label as follows:
yourTableViewCell *cell = (yourTableViewCell *)[[textField superview] superview];
cell.yourLabel.text = value;
/* u just give Tag to TextField and in textFieldDidEndEditing, save textfield text into an string and then reload the row...here is the code..also have sample */
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexpath
{
UITableViewCell *cell = [[UITableViewCell alloc] init];
UITextField *txtField1 = [[UITextField alloc]initWithFrame:CGRectMake(20, 10, 100, 80)];
txtField1.tag = indexpath.row;
txtField1.delegate= self;
[cell addSubview:txtField1];
UILabel *label1 = [[UILabel alloc] initWithFrame:CGRectMake(140, 10, 100, 80)];
[cell addSubview:label1];
//set text in label ** str1 comes from textFieldDidEndEditing
label1.text = str1;
return cell;
}
-(void)textFieldDidEndEditing:(UITextField *)textField
{
//save textField text to any string**declair it global
str1 = textField.text;
//reload selected row in table
NSIndexPath *durPath = [NSIndexPath indexPathForRow:textField.tag inSection:0];
NSArray *paths = [NSArray arrayWithObject:durPath];
[tbl reloadRowsAtIndexPaths:paths withRowAnimation:UITableViewRowAnimationRight];
}

using the return/next key to set focus on the following UITextField

I have several fields, lets say 5 for now. I would like to press the return/next key and aloud the user to skip from one to the other to enter data in each. I have a UITableViewCell
// Customize the appearance of table view cells.
- (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:CellIdentifier] autorelease];
UITextField *FirstField = [[UITextField alloc] initWithFrame:CGRectMake(10, 10, 130, 25)];
FirstField.delegate = self;
FirstField.tag = indexPath.row;
[cell.contentView addSubview:FirstField];
FirstField.returnKeyType = UIReturnKeyNext;
[FirstField release];
}
// Configure the cell...
return cell;
}
I am capturing every time the user presses the return/next key with the following:
// Handle any actions, after the return/next/done button is pressed
- (BOOL)textFieldShouldReturn:(UITextField *)textfield
But even if I know what cell/position/field, I am in, how do I tell the program focus on the next one? I know I have to use becomeFirstResponder, once I have the info.
You can do it by getting nextField using current tag
and make that Field as first responder.
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
int previouTag = textField.tag;
if (previouTag<=numberOfRows) {
UITextField *tempField=(UITextField *)[self.view viewWithTag:previouTag+1];
[tempField becomeFirstResponder];
}
}
`
-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
BOOL finedNext = NO;
int viewIndex = [self.mainScroll.subviews indexOfObject:textField];
for (int i = viewIndex+1; i < self.mainScroll.subviews.count; i++) {
if (!finedNext) {
UIView *view = [self.mainScroll.subviews objectAtIndex:i];
if ([view isKindOfClass:[UITextField class]]) {
finedNext = YES;
[view becomeFirstResponder];
}
}
}
return YES;
}
`

Getting/Setting UITextField value in a table cell

For my current project i need to have a table in which contains textfield in each cell, the number of cells and textfield must be dynamic, it's depends on the number of data in a MutuableArray. I have the textfield in cells working, but i can't get/set the textfield value. I wonder if you guys can help me out or at least correct me what I did wrong? Thank's alot in advance. See code snippets below:
// Adds textfield into cell
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSUInteger row = indexPath.row;
X10ArchiefIndexDefs *curIndex = [indexDefinities objectAtIndex:row];
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
BOOL bShowSelection = ([curIndex.HasVasteWaarden isEqualToString:#"false"]);
if (bShowSelection) {
bShowSelection = !([curIndex.DataType isEqualToString:#"Datum"]);
}
if ([indexPath section] == 0) {
if (bShowSelection) {
cell.accessoryType = UITableViewCellAccessoryNone;
} else {
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
}
UITextField *editField = [[UITextField alloc] initWithFrame:CGRectMake(110, 10, 185, 30)];
editField.adjustsFontSizeToFitWidth = YES;
editField.textColor = [UIColor blackColor];
editField.placeholder = curIndex.Naam;
editField.keyboardType = UIKeyboardTypeDefault;
editField.returnKeyType = UIReturnKeyNext;
editField.backgroundColor = [UIColor whiteColor];
editField.autocorrectionType = UITextAutocorrectionTypeNo; // no auto correction support
editField.autocapitalizationType = UITextAutocapitalizationTypeNone; // no auto capitalization support
editField.textAlignment = UITextAlignmentLeft;
editField.clearButtonMode = UITextFieldViewModeNever; // no clear 'x' button to the right
editField.tag = [curIndex.UID intValue];
[editField setEnabled: YES];
[cell addSubview:editField];
[editField release];
}
}
return cell;
}
In some case i'm using popovercontroller to display list of data. User can select a value uit of the popup. This code is executed when there is a value selected:
- (void)selectedValue:(NSString *) value {
//---update value of the text field ---
//The first attempt it doesn't put the text to text field
//static NSString *CellIdentifier = #"Cell";
//UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
//
//if (cell == nil) {
// cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
//}
// second attempt it crashes
X10ArchiefIndexDefs *curIndex = [indexDefinities objectAtIndex:curRow.row];
int index = [curIndex.UID intValue];
UITextField *textField = (UITextField *) [curCell viewWithTag: index];
if (textField) {
[textField setText:value];
}
[textField release];
[self.popOverController dismissPopoverAnimated:YES];
}
When cell is selected I'm making sure that the cell is saved for use later.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
X10ArchiefIndexDefs *curIndex = [indexDefinities objectAtIndex:indexPath.row];
if (!curIndex) {
return;
}
curRow = indexPath; // saves the selected row
if ([curIndex.VasteWaarden count] > 0) {
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
curCell = cell; // saves the selected cell
CGRect frame = [cell.superview convertRect:cell.frame toView:self.view];
self.detailViewController = [[DetailViewController alloc] initWithNibName:#"DetailViewController" bundle:nil];
detailViewController.delegate = self;
self.popOverController = [[[UIPopoverController alloc] initWithContentViewController:detailViewController] autorelease];
X10ArchiefIndexDefs *curIndex = [indexDefinities objectAtIndex:indexPath.row];
self.detailViewController.Values = curIndex.VasteWaarden;
[self.popOverController presentPopoverFromRect:frame inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
}
Again thank's alot in advance.
Cheers,
Inoel
In the second code snippet you are releasing the textField. You shouldn't do this because you haven't retained it. Because viewWithTag: simple gets a reference to the text field it doesn't retain the textField. So you are releasing it more times that it has been retained, so the retainCount reaches 0 and the textfield is dealloced from memory. Then when you attempt it the second time there is no textfield in the memory.
Just remove the:
[textField release];
From the second code snippet. If you don't understand why, then read some articles about memory management (just google it). It takes some time to understand it fully, at least I know it took me a while :)