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.
Related
I have a UITableView with some custom cells. In each cell, there is a ImageView and three labels and get the data from a string array. I have done the layout in my storyboard. The data source is a string array. This works.
Now I have insert a EditButton in the code. Now i can see the EditButton, but when I activate the edit mode the table cell will be resized, but the images and labels dont move.
Can you show me how to move the content of the cell? Who knows a tutorial with UITableView uses EditMode AND storyboards. All tutorials which I have found are based on the "old" Xcode.
Thank you very much
By the way, here is my code:
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
myData = [NSMutableArray arrayWithObjects:
#"Line1_Label1|Line1_Label2|Line1_Label3",
#"Line2_Label1|Line2_Label2|Line2_Label3",
#"Line3_Label1|Line3_Label2|Line3_Label3",
nil];
self.navigationItem.leftBarButtonItem = self.editButtonItem;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [myData count];
}
// Return a cell for the table
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// A cell identifier which matches our identifier in IB
static NSString *CellIdentifier = #"CellIdentifier";
// Create or reuse a cell
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Get the cell label using its tag and set it
NSString *currentItem = [myData objectAtIndex:indexPath.row];
NSArray *itemArray = [currentItem componentsSeparatedByString:#"|"];
UILabel *cellLabel = (UILabel *)[cell viewWithTag:1];
[cellLabel setText:itemArray[0]];
UILabel *cellLabel2 = (UILabel *)[cell viewWithTag:3];
[cellLabel2 setText:itemArray[1]];
UILabel *cellLabel3 = (UILabel *)[cell viewWithTag:4];
[cellLabel3 setText:itemArray[2]];
// get the cell imageview using its tag and set it
UIImageView *cellImage = (UIImageView *)[cell viewWithTag:2];
[cellImage setImage:[UIImage imageNamed: #"control.png"]];
return cell;
}
// Do some customisation of our new view when a table item has been selected
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Make sure we're referring to the correct segue
if ([[segue identifier] isEqualToString:#"ShowSelectedMovie"]) {
// Get reference to the destination view controller
ItemViewController *vc = [segue destinationViewController];
// get the selected index
NSInteger selectedIndex = [[self.tableView indexPathForSelectedRow] row];
// Pass the name and index of our film
[vc setSelectedItem:[NSString stringWithFormat:#"%#", [myData objectAtIndex:selectedIndex]]];
[vc setSelectedIndex:selectedIndex];
}
}
#end
First of all, make an IBOutlet of the tableview in the .h and synthesize it in the .m.
Then make an action to the edit button (if you don't already have one). In the action, write:
CGRect rect = yourTableView.cell.contentView.frame;
//Do whatever changes you wish to do with the sizing of the view. origin changes placement and size changes size (duh). Line below is an example.
rect.origin.y = yourTableView.cell.contentView.frame.origin.y - 20;
yourTableView.cell.contentView.frame = rect;
This won't be animated, but I think it'll fulfill your purpose.
Overwrite the -(void)layoutSubviews{} - method of your custom UITableViewCellController.m or if you don't use a custom UITableViewCellController, try it in your UITableViewController. But I haven't tried it yet with no custom UITableViewCellController.
Something like this will do the trick:
-(void) layoutSubviews {
[super layoutSubviews];
CGFloat xPositionOfElementInTableCell = 273.0f; /* the position of the element before going into edit mode */
if (self.isEditing && !self.showingDeleteConfirmation) // if we enter editing mode but not tapped on the red minus at the moment
{
xPositionOfElementInTableCell = 241.0f;
} else if (self.isEditing && self.showingDeleteConfirmation) // after we tappet on the red minus
xPositionOfElement = 193.0f;
}
CGRect frameOfElementInTableCell = self.myElementInTableCell.frame;
frameOfElementInTableCell.origin.x = xPositionofElement;
self.myElementInTableCell.frame = frameOfElementInTableCell;
}
I hope it helps you. The idea for this code is not mine. I found it here in SO, too. Don't know where exactly.
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 have gesture recognisers set up on my table view.
Swipe to the right and the accessory changes to an image of a tick
Swipe to the left and is changes to a chevron image
If a cell is tapped, it loads a local HTML file.
If you swipe to the right, the tick appears as it should. However, if you then tap a cell to view a HTML file and come back to the table view, the image reverts to the chevron.
What's the best way to ensure the tick stays as it should?
EDIT
Further code:
From 'viewDidLoad':
UISwipeGestureRecognizer *recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self
action:#selector(handleSwipeRight:)];
[recognizer setDirection:(UISwipeGestureRecognizerDirectionRight)];
[self.tableView addGestureRecognizer:recognizer];
recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self
action:#selector(handleSwipeLeft:)];
//recognizer.delegate = self;
[recognizer setDirection:(UISwipeGestureRecognizerDirectionLeft)];
[self.tableView addGestureRecognizer:recognizer];
- (void)handleSwipeLeft:(UISwipeGestureRecognizer *)gestureRecognizer
{
//Get location of the swipe
CGPoint location = [gestureRecognizer locationInView:self.tableView];
//Get the corresponding index path within the table view
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:location];
//Check if index path is valid
if(indexPath)
{
//Get the cell out of the table view
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
//Update the cell or model
cell.accessoryView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"disclosure.png"]];
}
}
- (void)handleSwipeRight:(UISwipeGestureRecognizer *)gestureRecognizer
{
CGPoint location = [gestureRecognizer locationInView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:location];
if(indexPath)
{
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
// cell.accessoryType = UITableViewCellAccessoryCheckmark;
cell.accessoryView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"tick.png"]];
}
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"MFGCell";
MFGCell *cell = (MFGCell *) [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"MFGCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
cell.itemTitle.text = [item objectAtIndex:indexPath.row];
cell.itemDescription.text = [description objectAtIndex:indexPath.row];
cell.itemImageView.image = [UIImage imageNamed:[icons objectAtIndex:indexPath.row]];
return cell;
}
In reaction to the user's swipe you should store the user's choice (e.g. in a private instance variable of type NSMutableArray). When the user comes back to the table view you can then reuse the information in your tableView:cellForRowAtIndexPath: to setup the cell with the correct accessory style.
Property declaration:
#property(nonatomic, retain) NSMutableArray* _accessoryStyle;
Synthesize the property. Then add this snippet to the bottom of handleSwipeLeft: to store the user's choice:
- (void)handleSwipeLeft:(UISwipeGestureRecognizer *)gestureRecognizer
{
[...]
NSNumber* number = [numberWithInt:0];
[_accessoryStyle replaceObjectAtIndex:indexPath.row withObject:number];
}
Add a similar snippet to the bottom of handleSwipeRight::
- (void)handleSwipeRight:(UISwipeGestureRecognizer *)gestureRecognizer
{
[...]
NSNumber* number = [numberWithInt:1];
[_accessoryStyle replaceObjectAtIndex:indexPath.row withObject:number];
}
In tableView:cellForRowAtIndexPath::
NSString* accessoryImageName;
NSNumber* number = [_accessoryStyle objectAtIndex:indexPath.row];
switch ([number intValue])
{
case 0:
accessoryImageName = #"disclosure.png";
break;
case 1:
accessoryImageName = #"tick.png";
break;
default:
// replace with your error handling code
return nil;
}
cell.accessoryView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:accessoryImageName]];
For all this to work you need to initialize the _accessoryStyle array with the same number of elements that you expect your table view to have cells. For instance, in your view controller's viewDidLoad:
- (void) viewDidLoad
{
[super viewDidLoad];
self._accessoryStyle = [NSMutableArray arrayWithCapacity:0];
NSNumber* defaultAccessoryStyle = [numberWithInt:0];
int numberOfRows = 17; // get the real number from somewhere
for (int index = 0; index < numberOfCells; ++index)
[_accessoryStyle addObject:defaultAccessoryStyle];
}
And to balance this you need to add
- (void) viewDidUnload
{
[super viewDidUnload];
self._accessoryStyle = nil;
}
There is still much room for improvement:
Find better variable names
Use an enumeration for the different styles instead of just hardcoded numbers 0 and 1
Do not allocate a new UIImageView for each table view cell, just allocate two of them and use the right one depending on the accessory style
For your problem, there is an underlying logic issue because there is either a swipe left event firing when it should not or the views are just being unloaded and resetting to default. See if you can log when the events fire; otherwise the state of the view should be preserved. Also what I would do is add an extra state variable like int currentCellState that you change when you enter your different states to keep track of your states. Then in your viewDIdLoad make sure that all your data and your view are in sync, ie the value of currentCellState matches the state of your view.
The best way to do this is to put the images/buttons you have in an array, and each time the view loads it shows the item which index is selected..
in order to do this, the swipeMethode should be modified to something like this
-(void)swipeMethod: (UISwipeGestureRecognizer *) sender
{
if(sender.direction ==
UISwipeGestureRecognizerDirectionLeft && index < [myArray count]){
[self setSelectedIndex:index+1 animated:YES];
index++;
}else if (sender.direction == UISwipeGestureRecognizerDirectionRight && index > 0) {
[self setSelectedIndex:index-1 animated:YES];
index--;
}else {
return;
}
}
in the viewDidLoad add this code:
leftRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(swipeMethod:)];
[leftRecognizer setDirection: UISwipeGestureRecognizerDirectionLeft];
[self.tableView addGestureRecognizer:leftRecognizer];
rightRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(swipeMethod:)];
[rightRecognizer setDirection: UISwipeGestureRecognizerDirectionRight];
[self.tableView addGestureRecognizer:rightRecognizer];
I have been trying to figure this out for a bit. I create a custom cell in its own xib file. In my view controller I have setup a table view controller with sections. The data that is being pulled into the table View is based off a fetch request controller from some core data that I have. I set up the custom cell in the cellForRowAtIndexPath function. I am creating a label for each cell within this function and populating the label with some data from the managed object. Everything seems ok when I first run. However, when I try to scroll up and down and new cells are reused the data in the labels are placed in the wrong cells. I have seen and heard this has to do with the reuse of cells. However, have not seen much examples on correcting this issue. Below is some of the code I have in my cellForRowAtIndexPath function. Let me know if any other input may be needed. Thanks for any help.
-(UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [aTableView dequeueReusableCellWithIdentifier:#"CustomCell"];
/* do this to get unique value per cell due to sections. */
NSInteger indexForCell = indexPath.section * 1000 + indexPath.row + 1;
NSManagedObject *managedObject = [fetchedResultsController objectAtIndexPath:indexPath];
NSString *lastSession = nil;
UILabel *lastSessionLabel = nil;
if(cell == nil) {
lastSession = [managedObject valueForKey:#"last_session"];
[self.tableView registerNib:[UINib nibWithNibName:#"CustomCell"
bundle:[NSBundle mainBundle]]
forCellReuseIdentifier:#"CustomCell"];
self.tableView.backgroundColor = [UIColor clearColor];
cell = [aTableView dequeueReusableCellWithIdentifier:#"CustomCell"];
lastSessionLabel = [[UILabel alloc]initWithFrame:CGRectMake(410,55, 89, 35)];
lastSessionLabel.textAlignment = UITextAlignmentLeft;
lastSessionLabel.tag = indexForCell;
lastSessionLabel.font = [UIFont systemFontOfSize:17];
lastSessionLabel.highlighted = NO;
lastSessionLabel.backgroundColor = [UIColor clearColor];
cell.contentView.tag = indexForCell;
[cell.contentView addSubview:lastSessionLabel];
} else {
lastSessionLabel = (UILabel *)[cell viewWithTag:indexForCell];
}
if (lastSession && lastSession.length) {
lastSessionLabel.text = lastSession;
}
cell.textLabel.text = [NSString stringWithFormat:#"%#%#%#%#", #"Dr. ",
[managedObject valueForKey:#"first_name"],
#" " ,
[managedObject valueForKey:#"last_name"]];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.editingAccessoryType = UITableViewCellAccessoryNone;
return cell;
}
** Revised Code **
Below are the changes to code: in viewDidLoad is the following:
- (void)viewDidLoad
{
[super viewDidLoad];
[self.tableView registerNib:[UINib nibWithNibName:#"CustomCell"
bundle:[NSBundle mainBundle]]
forCellReuseIdentifier:#"CustomCell"];
self.tableView.backgroundColor = [UIColor clearColor];
}
in -(UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath: (NSIndexPath *)indexPath {
UITableViewCell *cell = [aTableView dequeueReusableCellWithIdentifier:#"CustomCell"];
NSInteger indexForCell = indexPath.section * 1000 + indexPath.row + 1;
NSLog(#"index for cell: %d",indexForCell);
NSManagedObject *managedObject = [fetchedResultsController objectAtIndexPath:indexPath];
NSString *lastSession = [managedObject valueForKey:#"last_session"];
UILabel *lastSessionLabel = nil;
if(cell == nil) {
NSLog(#"Cell is nil! %#", [managedObject valueForKey:#"first_name"]);
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"CustomCell"];
self.tableView.backgroundColor = [UIColor clearColor];
}
lastSessionLabel = [[UILabel alloc]initWithFrame:CGRectMake(410,55, 89, 35)];
lastSessionLabel.textAlignment = UITextAlignmentLeft;
lastSessionLabel.tag = indexForCell;
lastSessionLabel.font = [UIFont systemFontOfSize:17];
lastSessionLabel.highlighted = NO;
lastSessionLabel.backgroundColor = [UIColor clearColor];
[cell.contentView addSubview:lastSessionLabel];
/* Appropriate verbiage for nil last session. */
if (lastSession && lastSession.length) {
lastSessionLabel.text = lastSession;
}
return cell;
}
I am still having issues again with the label cell text changing when I scroll for different cells. I read some where about maybe having to use the prepareForReuse function for this.
You are only fetching lastSession when you create a new cell. Try putting this line before the if(cell == nil) statement.
lastSession = [managedObject valueForKey:#"last_session"];
I.e. this:
NSString *lastSession = [managedObject valueForKey:#"last_session"];
in stead of this:
NSString *lastSession = nil;
UPDATE
You are also setting the same tag for two views:
lastSessionLabel.tag = indexForCell;
...
cell.contentView.tag = indexForCell;
Based on your code sample you should only use the first line, i.e. set the tag for the lastSessionLabel
SECOND UPDATE
You should also only call registerNib: once in your view lifecycle, e.g. in viewDidLoad, not every time you need a new cell. Furthermore, you should create a new cell if cell == nil in stead of using dequeueReusableCellWithIdentifier:. E.g.
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"CustomCell"];
I have a UITableView that has 1 blank row at the top of it, and I cannot figure out why. Here is the relevant code, do you folks have any idea what's going on here?
The UITableView loads up with no content. This method is what kicks off each data refresh after:
- (IBAction)updateButton:(id)sender
{
if (questionsTextField.isFirstResponder) {
[questionsTextField resignFirstResponder];
[self assignQuestionsCount];
}
if (currentNumberOfQuestions > 0) {
// do work calculating
currentTest = nil;
currentTest = [self retrieveCurrentTest];
currentTest.numberOfQuestions = currentNumberOfQuestions;
currentTest.decimalPlacesToDisplay = 0;
currentTest.roundingBreakPoint = 0.5;
currentGradeScale = nil;
currentGradeScale = [currentTest generateGradingScale];
[scoresTableView reloadData];
}
else {
// my error handling on text boxes here....
}
}
Here is my implementation of the UITableView methods:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.currentGradeScale count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"scoresIndentifier";
static int missedTag = 1, correctTag = 2, gradeTag = 3;
UILabel *missedLabel, *correctAndTotalLabel, *letterGradeLabel;
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
//if a cell does not exist, get it then initialize it
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
// populate data
missedLabel = [[UILabel alloc] initWithFrame:CGRectMake(0.0, 0.0, 100, 50)];
missedLabel.tag = missedTag;
missedLabel.font = [UIFont systemFontOfSize:14.0];
missedLabel.textAlignment = UITextAlignmentCenter;
missedLabel.textColor = [UIColor blackColor];
missedLabel.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleHeight |UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleWidth;
[cell.contentView addSubview:missedLabel];
}
// if it does, just reassign the properties
else {
missedLabel = (UILabel *)[cell.contentView viewWithTag:missedTag];
}
missedLabel.text = [[self.currentGradeScale objectAtIndex:indexPath.row] determineLetterGrade:0.5];
return cell;
}
Thanks for the help folks, I really appreciate it.
The most obvious explanation which you've probably already considered is that the first row of the table has been set with blank data (i.e. self.currentGradeScale objectAtIndex:0 returns nil or #"" for "determined letter grade 0.5.")
If you put a breakpoint on cellForRowAtIndexPath in the debugger at the line where you assign a value to the label text is it definitely setting a non-null/non-blank value for row 0?
Also side note there is a memory leak on missedLabel - adding it as a subview to the cell will retain it so you should autorelease on alloc, or release after adding as a subview.
I had this same problem and found that there was a value in the Scroll View Size / Content Insets / Top area. See attached image. Once I set that to 0 and saved, the blank area at the top went away. I hope this helps.