I have a single textField in the cell allocation section and after this section I try to provide give the text field various arguments.
Works fine no problem till here, the problem lies how to handle which textField is returning in the delegate method.
My Earlier approach was to simply allocate different text fields for different user input, simple but produces UI glitch when there are many textField(s), hence want avoid it.
for better understanding here is sample code for table delegate method cellAtIndexRow
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellTableIdentifier = #"CellTableIdentifier";
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellTableIdentifier];
if (cell == nil) {
// Create a new cell. CGRectZero allows the cell to determine the appropriate size.
CGRect cellFrame = CGRectMake(0,0,300,65);
cell = [[[UITableViewCell alloc] initWithFrame:cellFrame reuseIdentifier:CellTableIdentifier] autorelease];
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(8,4,284,25)];
textField.delegate = self;
textField.returnKeyType = UIReturnKeyDone;
textField.tag = kTagAddContactTextField;
textField.backgroundColor = [UIColor orangeColor];
[cell.contentView addSubview:textField];
[textField release];
}
UITextField *textField = (UITextField*)[cell.contentView viewWithTag:kTagAddContactTextField];
switch (indexPath.row) {
case 0:
[textField setPlaceholder:#"First Name"];
break;
case 1:
[textField setPlaceholder:#"Last Name"];
break;
case 2:
[textField setPlaceholder:#"Email"];
textField.autocorrectionType = UITextAutocorrectionTypeNo;
textField.autocapitalizationType = UITextAutocapitalizationTypeNone;
textField.keyboardType = UIKeyboardTypeEmailAddress;
break;
}
//cell.textLabel.text = #"Test";
return cell;
}
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField{
//here is the place where I wann to handle various text fields and store there values.
return YES;
}
Try pulling
textField.tag = kTagAddContactTextField;
out of the table cell creation code, and assign a different tag value for each row in your UITable.
switch (indexPath.row) {
case 0:
textField.tag = kFirstNameField;
[textField setPlaceholder:#"First Name"];
break;
case 1:
textField.tag = kLastNameField;
[textField setPlaceholder:#"Last Name"];
break;
case 2:
textField.tag = kEmail;
[textField setPlaceholder:#"Email"];
textField.autocorrectionType = UITextAutocorrectionTypeNo;
textField.autocapitalizationType = UITextAutocapitalizationTypeNone;
textField.keyboardType = UIKeyboardTypeEmailAddress;
break;
}
Then you can distinguish which text field you're getting by the tag returned.
you can use "tag" property of UIView (which UITextField inherits).
e.g.
switch (indexPath.row) {
case 0:
[textField setPlaceholder:#"First Name"];
textField.tag=1;//Name
break;
case 1:
[textField setPlaceholder:#"Last Name"];
textField.tag=2;//Surname
break;
case 2:
[textField setPlaceholder:#"Email"];
textField.tag=3;//Email
textField.autocorrectionType = UITextAutocorrectionTypeNo;
textField.autocapitalizationType = UITextAutocapitalizationTypeNone;
textField.keyboardType = UIKeyboardTypeEmailAddress;
break;
}
and in your callback:
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField{
//here is the place where I wann to handle various text fields and store there values.
switch(textField.tag)
{
case 1://Name
// do stuff;
break;
case 2://Surname
// do stufff;
break;
case 3://Email
//do stuff;
break;
}
return YES;
}
Several ways of varying ickiness:
Use different reuse identifiers and tags for each kind of cell, and switch on the tag. This means cells aren't reused as they might otherwise be, but this is not the end of the world.
Follow UIView.superview until you find a subclass of UITableViewCell (textField.superview.superview should work, but this may change in future versions of iPhone OS), and then use [tableView indexPathForRow:cell].
Use different reuse identifiers (but the same tag), follow the superview chain until you find a UITableViewCell and look at its reuse identifier.
Use a custom UITableViewCell subclass that stores a NSString* or NSInteger key so you know what kind of cell it is (optionally, make the cell the text field's delegate and have the cell notify the view controller of the change).
Switch on the placeholder text (very icky when it comes to i18n)
Whenever the user chose a textfield for editing didSelectRowAtIndexPath should get called. There you can switch the value an int property currentEdited from which value you can detect what the user was changing.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
switch(indexPath.row)
{
case 0:currentEditing = kEditingFirstName;
break;
case 1:....
...
}
}
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField
{
switch(currentEditing)
{
case kEditingFirstName:
//store first name
break;
....
}
return YES;
}
The tagging thing used in the other answers could lead to problems because of the re-use of the textfield.
Related
I have an NSCollectionView that has 3 sections which contains colors from a color palette. I want each section to have a header view with the name of the section. At first glance, it appears to work. On launch, it looks like this:
However, as soon as I resize the window, the header text ends up drawing outside the headers (and also inside it, somehow!):
In order to have headers in the collection view, I have a header view class named CollectionHeaderView. I register this class as a supplemental view:
[_collection registerClass:[CollectionHeaderView class]
forSupplementaryViewOfKind:#"UICollectionElementKindSectionHeader"
withIdentifier:kSupplementalView];
In the collection view's delegate, I implement the method to return the view for the supplemental element:
- (NSView *)collectionView:(NSCollectionView *)collectionView
viewForSupplementaryElementOfKind:(NSCollectionViewSupplementaryElementKind)kind
atIndexPath:(NSIndexPath *)indexPath {
NSView* result = [collectionView makeSupplementaryViewOfKind:kind
withIdentifier:kSupplementalView
forIndexPath:indexPath];
if ([kind isEqualToString:#"UICollectionElementKindSectionHeader"]) {
NSTextField* textView = ((CollectionHeaderView*)result).textField;
switch (indexPath.section) {
case 0:
[textView setStringValue:#"Bright Colors"];
break;
case 1:
[textView setStringValue:#"Pastel Colors"];
break;
case 2:
[textView setStringValue:#"Designer Colors"];
break;
}
return textView;
}
return nil;
}
Furthermore, if I resize the window, the header views do not move. The collection elements seem to flow around the headers, leaving things listed under the wrong section. And, as you can see in the second picture above, widening the window ends up leaving a gap between the right edge of the header and the right edge of the collection view.
The CollectionHeaderView class is very simple. It just creates a text field and draws the background and the text field:
#implementation CollectionHeaderView
- (instancetype)initWithFrame:(NSRect)frameRect {
self = [super initWithFrame:frameRect];
if (self != nil) {
NSRect textFrame = frameRect;
_textField = [[NSTextField alloc] initWithFrame:textFrame];
_textField.editable = NO;
_textField.bordered = NO;
_textField.font = [NSFont fontWithName:#"Helvetica-Bold" size:14.0];
_textField.backgroundColor = [NSColor colorWithSRGBRed:0.0 green:0.0 blue:0.0 alpha:0.0];
[self addSubview:_textField];
self.identifier = kSupplementalView;
}
return self;
}
- (void)drawRect:(NSRect)dirtyRect {
[super drawRect:dirtyRect];
// Drawing code here.
NSBezierPath* fillPath = [NSBezierPath bezierPath];
[fillPath appendBezierPathWithRect:dirtyRect];
[[NSColor lightGrayColor] setFill];
[fillPath fill];
[_textField drawRect:dirtyRect];
}
#end
Have I implemented any of the above methods incorrectly? Is there any method I need to implement that I haven't?
The return value of collectionView:viewForSupplementaryElementOfKind:atIndexPath: is the supplementary view result.
- (NSView *)collectionView:(NSCollectionView *)collectionView
viewForSupplementaryElementOfKind:(NSCollectionViewSupplementaryElementKind)kind
atIndexPath:(NSIndexPath *)indexPath {
NSView* result = [collectionView makeSupplementaryViewOfKind:kind
withIdentifier:kSupplementalView
forIndexPath:indexPath];
if ([kind isEqual:NSCollectionElementKindSectionHeader]) {
NSTextField* textView = ((CollectionHeaderView*)result).textField;
switch (indexPath.section) {
case 0:
[textView setStringValue:#"Bright Colors"];
break;
case 1:
[textView setStringValue:#"Pastel Colors"];
break;
case 2:
[textView setStringValue:#"Designer Colors"];
break;
}
return result;
}
return nil;
}
I'm trying to print out the value of where the user clicked in a method that is called when a user updates the value of a UISwitch in some of the cells. There are four cells that have the UISwitch set as an accessory of the cell. I already have the infrastructure in place to check against the values of calling [self.basicObjects objectAtIndex:indexPath.row], but the problem is, that no matter which cell I press, the 0 value of the NSMutableArray that contains the titles of the four cells is called.
- (void)switchChanged:(id)sender cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"self.basicObjects value: %#", [self.basicObjects objectAtIndex:indexPath.row]);
}
As a side note, as I was looking at similar questions, it also seemed important to note that self.settingsTable is a grouped UITableView with these four cells being in section 1 (0, 1, 2). The other two sections do not contain any UISwitch as an accessory type, it's only this section, and only this one the references the switchChanged:cellForRowAtIndexPath: method.
Edit - 7:31pm
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"TableCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:simpleTableIdentifier];
}
cell.textLabel.font = [UIFont fontWithName:#"HelveticaNeue-Light" size:17.5];
if (indexPath.section == 0)
{
// change the text to standard case
// change text color
}
else if (indexPath.section == 1)
{
cell.textLabel.text = [self.basicObjects objectAtIndex:indexPath.row];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
self.switchProperty = [[UISwitch alloc] initWithFrame:CGRectZero];
cell.accessoryView = self.switchProperty;
if ([[self.basicStatus objectAtIndex:indexPath.row] isEqual:#"YES"])
{
[self.switchProperty setOn:YES animated:YES];
[self.switchProperty addTarget:self action:#selector(switchChanged:cellForRowAtIndexPath:) forControlEvents:UIControlEventValueChanged];
}
else if ([[self.basicStatus objectAtIndex:indexPath.row] isEqual:#"NO"])
{
[self.switchProperty setOn:NO animated:YES];
[self.switchProperty addTarget:self action:#selector(switchChanged:cellForRowAtIndexPath:) forControlEvents:UIControlEventValueChanged];
}
}
else if (indexPath.section == 2)
{
cell.textLabel.text = [self.objects objectAtIndex:indexPath.row];
cell.detailTextLabel.text = [self.objectsType objectAtIndex:indexPath.row];
cell.detailTextLabel.font = [UIFont fontWithName:#"HelveticaNeue-Light" size:17.5];
if ([[self.objectsStatus objectAtIndex:indexPath.row] isEqual:#"Setup"])
cell.detailTextLabel.textColor = [UIColor colorWithRed:0.298 green:0.851 blue:0.392 alpha:1]; // #4CD964 (green)
else if ([[self.objectsStatus objectAtIndex:indexPath.row] isEqual:#"Not Setup"])
cell.detailTextLabel.textColor = [UIColor colorWithRed:0.898 green:0.267 blue:0.267 alpha:1]; // #E54444 (red)
}
return cell;
}
You can't pass the indexPath in your action method that way. You can only pass the sender, and optionally, the event that triggered the action. You need to get the indexPath a different way. One common way is to give the switch a tag that's equal to the indexPath.row, and use that tag as an index into your array.
Here's a problem. You can't send the second parameter like this.
[self.switchProperty addTarget:self action:#selector(switchChanged:cellForRowAtIndexPath:) forControlEvents:UIControlEventValueChanged];
I recommend that you set a tag and use it like as below.
[self.switchProperty setTag:indexPath.row];
[self.switchProperty addTarget:self action:#selector(switchChanged:) forControlEvents:UIControlEventValueChanged];
and in switchChanged: will be...
- (void)switchChanged:(id)sender
{
NSLog(#"self.basicObjects value: %#", [self.basicObjects objectAtIndex:[sender tag]]);
}
I am making a form within a grouped tableview. In this form I have UIswitches and textfields. But after scrolling down, the cells styles are changing.
Here is my cellForRowAtIndex
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = nil;
static NSString *MyIdentifier = #"GenericCell";
cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:MyIdentifier] ;
}
NSString *text = nil;
if(indexPath.section == CREDENTIALS_SECTION){
if (indexPath.row == 0) {
NSLog(#"tot hier login");
UITextField *login = [[UITextField alloc] initWithFrame:CGRectMake(110, 10, 185, 30)];
login.adjustsFontSizeToFitWidth = YES;
login.placeholder = #"example#gmail.com";
login.keyboardType = UIKeyboardTypeEmailAddress;
login.returnKeyType = UIReturnKeyNext;
login.backgroundColor = [UIColor clearColor];
login.tag = 0;
login.delegate = self;
[login setEnabled: YES];
[cell addSubview:login];
}else if (indexPath.row == 1){
NSLog(#"tot hier pass");
UITextField *pass = [[UITextField alloc] initWithFrame:CGRectMake(110, 10, 185, 30)];
pass.adjustsFontSizeToFitWidth = YES;
pass.placeholder = #"Required";
pass.keyboardType = UIKeyboardTypeDefault;
pass.returnKeyType = UIReturnKeyDone;
pass.secureTextEntry = YES;
pass.backgroundColor = [UIColor clearColor];
pass.tag = 0;
pass.delegate = self;
[cell addSubview:pass];
}
if (indexPath.row == 0) { // Email
text = #"Email";
}
else if(indexPath.row == 1) {
text = #"Password";
}
}else if(indexPath.section == METHODS_SECTION){
UISwitch *toggleSwitch = [[UISwitch alloc]initWithFrame:CGRectMake(220, 10, 100, 30)];
toggleSwitch.tag = indexPath.row;
[toggleSwitch addTarget:self action:#selector(toggleSwitched:) forControlEvents:UIControlEventValueChanged];
[cell addSubview:toggleSwitch];
if (indexPath.row == 0) { // Web
text = #"Web applicatie";
}
else if(indexPath.row == 1) { //Mobile
text = #"Mobiele applicatie";
}
else if(indexPath.row == 2) { //Mail
text = #"E-mail";
}
}else if(indexPath.section == PHONE_SECTION){
UITextField *phoneText = [[UITextField alloc] initWithFrame:CGRectMake(20, 10, 185, 30)];
phoneText.adjustsFontSizeToFitWidth = YES;
phoneText.font = [UIFont fontWithName:#"Arial-BoldMT" size:18];
phoneText.keyboardType = UIKeyboardTypeNumberPad;
phoneText.delegate = self;
phoneText.textColor = [UIColor blackColor];
phoneText.text = _person.phone;
[cell addSubview:phoneText];
}else if(indexPath.section == REMARK_SECTION){
UITextView *textView = [[UITextView alloc]initWithFrame:CGRectMake(20, 10, 280, 260)];
textView.text = _person.remark;
textView.delegate = self;
textView.font = [UIFont fontWithName:#"Arial" size:15.0];
textView.backgroundColor = [UIColor clearColor];
[cell addSubview:textView];
text = #"";
}else if(indexPath.section == BUTTON_SECTION){
cell.backgroundColor = [UIColor redColor];
text = #"test";
}
cell.textLabel.text = text;
return cell;
}
After some searching I found that more people are having this problem. And that the problem lays in this piece of code.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = nil;
static NSString *MyIdentifier = #"GenericCell";
cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:MyIdentifier] ;
}
NSString *text = nil;
But I don't find a solution for it.
Hope anybody can help!
Kind regards!
Clarification
Oké so here you see a screenshot of my form. below I have a red cell (save button) when I scroll down other cells are getting a red background. And some cells, text property's are changing.
That is not gong to work. Aparently you did not yet fully understand how the re-use mechanism works.
What do you do?
First you fetch a cell to be re-used. If you get one -fine so far but the problem comes later. If you don't get one then you create a new one.
When you have created a new one, which is the case at start before the user begins scrolling, then you add some UIItems depending on section and row. I will explain why this is not actually a smart thing to do.
Then the user scrolls. Cells will dissappear from screen and then made available for re-use. Then you will fetch the cells for re-use. But it may well happen that those cells already have additional UI-Items on them because you have used them before in that way. In the following process you will add new UI Items regardless whether there are already additional UI-Items on that very cell.
What can you do:
Create your own custom table cell subclasses. One subclass for each set of additional ui items that you may need. That is probably the neatest way of doing it. For each subclass use a different re-use identifier (!!!)
This is what I would recommend!
However, there are alternatives:
You could still live with your concept but invent an individual type of re-use identfier for each type of cell that has some type of additional ui item on it. If so, then make sure that these UI items are only created and added as sub-views in the if (cell == nil) branch of your code. Only create them once and then re-use them. Cell reuse-IDs could be "email-display", "email-input" , "password-display", "password-input", "switch", ...
A variance of the solution above would be, to calculate row and section
into the reuse-identifier. Such as "cell-id-0.2" for section 0 and
row 2 - or so. But still you will have to make sure that you really
re-use the additional UI views and do not re-create them every time
when the cell is filled with data. Plus, the layout in your first section varies depending on whether you want to input password and e-mail or just display them. You will still have to deal with those variations.
If cell == nil - meaning if a cell is re-used - then first clean it from every UI item that you may have added before. You can do that by tagging your UIViews with - let's say 99 - (anything different from 0 should do) upon creation and when reusing enumerate over all subviews and remove those, which have the tag 99. Despite that you can stick with the code that you have already made.
The easiest fix is:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"GenericCell"] ;
//some more code
return cell;
}
This would remove the reusability from the tableview, but since it's a limited settings view, it can be ok. I would still advice taking 1 or 2 from Hermann Klecker's solutions.
If you also need to persist UIControl state then use
static NSString *MyIdentifier = [NSString stringWithFormat:#"GenericCell%d",indexPath.row];
It will always return your unique table row and you can use it as required.
Try to remove all subviews from cell before reusing it. Try the code :
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:MyIdentifier] ;
}
else
{
[cell.contentView.subviews makeObjectsPerformSelector:#selector(removeFromSuperview)];
}
Remove all subviews before adding the subviews on cell.
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:SimpleTableIdentifier]autorelease];
}
else
{
//To remove the subview of cell.
for (UIView *vwSubviews in [cell.contentView subviews])
{
[vwSubviews removeFromSuperview];
}
}
It may solves your problem.
Actually you have some bad code here.
In the mehthod
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
Unless it is not in if (cell == nil), you should NOT initialize and use any
-(void)addSubview:(UIView*)view
Why?
The cells are views which are reused from tableview. So If you add some subview, next time while reusing the cell, it will be added more subviews on it. Simply they are overlapped and may cause MEMORY LEAK.
Do not forget that cells are reusable. So;
if I have the following code unless I do not set text somewhere else. It is expected to all cells has the text in their text labels "this is a text". Because they are reusable.
if (someChangingBool) {
cell.textLabel.text = #"this is a text";
}
So I need to have an else for that if which sets the text something else.
For more Information.
I'm trying to make a UIBarButtonItem in the right-corner of my tableView in order to highlight and un-highlight a cell when pressed.
In less words, when users press the button, a range of cells will change their background color from white to yellow.
I'm failing to make that though, because every time i press that button the app crashes.
Here's the code i'm using to create the button:
- (void)viewDidLoad {
[super viewDidLoad];
UIBarButtonItem *barButton;
barButton = [[[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:#"high.png"] style:UIBarButtonItemStyleBordered target:self action:#selector(colorCells:)] autorelease];
self.navigationItem.rightBarButtonItem = barButton;
}
And here to make it highlight a range of cells:
- (void) colorCells:(id)sender
{
UITableViewCell *cell;
NSString *cellValue = cell.textLabel.text;
if ([cellValue isEqual: #"textTheCellShouldBeEqualTo"]){
cell.backgroundColor = [UIColor colorWithRed:251/255.0f green:255/255.0f blue:192/255.0f alpha:1]; ;
cell.imageView.image = [UIImage imageNamed:#"hot.png"];
}
else {
cell.imageView.image = nil;
cell.backgroundColor = [UIColor whiteColor];
}
}
Where am i failing? It's supposed to work fine. Or? Am i missing something? The view is a UITableViewController.
EDIT
I modified my code like so:
- (void) colorCells:(id)sender{
UITableViewCell *cell;
NSInteger nSections = [self.tableView numberOfSections];
for (int j=0; j<nSections; j++) {
NSInteger nRows = [self.tableView numberOfRowsInSection:j];
for (int i=0; i<nRows; i++) {
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:i inSection:j];
cell = [self.tableView cellForRowAtIndexPath:indexPath];
}
NSString *cellValue = cell.textLabel.text;
if ([cellValue isEqual: #"textTheCellShouldBeEqualTo"] ){
cell.backgroundColor = [UIColor colorWithRed:251/255.0f green:255/255.0f blue:192/255.0f alpha:1]; ;
cell.imageView.image = [UIImage imageNamed:#"hot.png"];
}
else {
cell.imageView.image = nil;
cell.backgroundColor = [UIColor whiteColor];
}
[self.tableView reloadData];
}
}
Now it doesn't crash, but it doesn't color the background too. Any ideas?
Basing the background color off of the text in a cell seems incredibly fragile. What determines that a cell should be highlighted? Does it change? Surely, the color of the background corresponds to a specific property of the objects in your data source. A more robust approach would be to use an NSMutableIndexSet property on your class to track a set of row indexes require highlighting upon tapping the bar button.
Consider this example. I'm assuming that rowsToHighlight is an instance of NSMutableIndexSet declared in your class and that it has been populated with the indexes of rows that require highlighting. We're going to implement -tableView:willDisplayCell:forRowAtIndexPath: to adjust the background color of the cell depending if the provided index path is a member of rowsToHighlight.
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([self.rowsToHighlight containsIndex:indexPath.row])
{
cell.backgroundColor = [UIColor yellowColor];
}
}
Then in the method that is fired by your bar button, just do an empty update block to get the table to reload with animation.
- (void)colorCells:(id)sender
{
[self.tableView beginUpdates];
[self.tableView endUpdates];
}
Your cells won't redraw unless you tell the table view which contains them to reload them. You can do this with one of several methods. You may consider [someTableView reloadData] or one of these methods.
Also, your cell object is not the one in your table view. You might consider this:
- (void) colorCells:(id)sender
{
UITableViewCell *cell;
//grab a cell
cell = [self tableView:self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:someRow inSection:someSection]];
NSString *cellValue = cell.textLabel.text;
if ([cellValue isEqual: #"textTheCellShouldBeEqualTo"]){
cell.backgroundColor = [UIColor colorWithRed:251/255.0f green:255/255.0f blue:192/255.0f alpha:1]; ;
cell.imageView.image = [UIImage imageNamed:#"hot.png"];
}
else {
cell.imageView.image = nil;
cell.backgroundColor = [UIColor whiteColor];
}
//perhaps you need to reload the table as well
[self.tableView reloadData];
}
I am trying to cycle/navigate through the UITextFields which I added as subviews to the UITableViewCells. However I am unable to get my nextResponder value in the textFieldShouldReturn: method. Can anyone advise me where my code went wrong?
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString* PlaceholderCellIdentifier = #"PlaceholderCell";
UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:PlaceholderCellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:PlaceholderCellIdentifier] autorelease];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.textLabel.font = [UIFont boldSystemFontOfSize:14];
}
if (indexPath.row == 0) // first name
{
cell.textLabel.text = #"First Name:";
UITextField *tempFirstNameField = [[UITextField alloc]initWithFrame:CGRectMake(100, (44-18)/2, 320-100, 32)];
self.firstNameField = tempFirstNameField;
self.firstNameField.font = [UIFont systemFontOfSize:14];
self.firstNameField.tag = 1;
self.firstNameField.returnKeyType = UIReturnKeyNext;
self.firstNameField.delegate = self;
[tempFirstNameField release];
[cell.contentView addSubview:self.firstNameField];
}
else if (indexPath.row == 1) //last name
{
cell.textLabel.text = #"Last Name:";
UITextField *tempLastNameField = [[UITextField alloc]initWithFrame:CGRectMake(100, (44-18)/2, 320-100, 32)];
self.lastNameField = tempLastNameField;
self.lastNameField.font = [UIFont systemFontOfSize:14];
self.lastNameField.tag = 2;
self.lastNameField.returnKeyType = UIReturnKeyNext;
self.lastNameField.delegate = self;
[tempLastNameField release];
[cell.contentView addSubview:self.lastNameField];
}
return cell;
}
-(BOOL)textFieldShouldReturn:(UITextField*)textField;
{
NSInteger nextTag = textField.tag + 1;
NSLog(#"next tag %i",nextTag);
// Try to find next responder
UIResponder* nextResponder = [textField.superview.superview viewWithTag:nextTag];
//This always returns me null value
NSLog(#"next responder %#", nextResponder);
if (nextResponder) {
// Found next responder, so set it.
[nextResponder becomeFirstResponder];
} else {
// Not found, so remove keyboard.
[textField resignFirstResponder];
}
return NO; // We do not want UITextField to insert line-breaks.
}
Why do you need a tableView for that, your fields seem to be static. Use a simple scrollview if the content is larger than you screen.
To loop your fields you can :
1/ use a container view for all controls you want in your navigation loop and simply loop in your subviews NSArray
2/ best choice. Use the NSUInteger tag field to set the order in which the controls should get the focus. Begin at non-zero value because 0 is the default tag value. 10,11,12,13 and use viewWithTag: on your container view to retrieve the next control.
UITableView is not an array - it may reload or even release any cell when it's invisible.
If you would like to operate created cells - it's better to create them all, put in an array and then display them from the array. I.e. create them all before table start loading, but not in cellForRowAtIndexPath method. It may be done in ViewWillAppear, for example.
In this case all of your objects will be retained by the array and not released until you wish to.