I have used Cell.ContentView in my implementation for customizing the cell contents. It works fine but the only problem is when I have many cells and I scroll them up and down, the cell contents gets overwritten into the cells just become hidden followed by visible. Suppose I scroll first cell up and then again takes it down, the last cell's contents gets overwritten on first cell!!
I debugged enough on this but couldn't find the exact solution. I tried checking Cell.ContentView.SubViews count and if it 0 then only add other subviews. This doesn't display any cell contents until I scroll them up and down but once contents appeared, it doesn't overwrite..Little bit strange..!! I also made sure that I am using reusing the cell correctly. Following is my code that adds subviews into cell's contentview. Please let me know how could I get rid of this issue.
P.S: Don't worry about the variables and calculations I have done. Assume that it returns correct values. :)
- (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];
}
NSInteger totalAvailableSpace = IPHONE_DISPLAY_WIDTH - iconSize - accesorySize - 10;
NSInteger lableHeight = [[cellDetails objectForKey:#"TableItemTextFontSize"] intValue] * 2 + 10;
UILabel *textLabel = nil;
textLabel = [[[UILabel alloc] initWithFrame:CGRectMake(iconSize+12, self.tableCellHeight/2 - lableHeight/2, totalAvailableSpace * 0.8, lableHeight)] autorelease];
textLabel.numberOfLines = 2;
textLabel.lineBreakMode = UILineBreakModeWordWrap;
textLabel.textAlignment = UITextAlignmentLeft;
textLabel.text = [cellDetails objectForKey:#"TableItemMainText"];
if ([textLableColor scanHexInt:&hex]) {
textLabel.textColor = UIColorFromRGB(hex);
}
textLabel.font = [UIFont fontWithName:[cellDetails objectForKey:#"TableItemTextFontName"] size:[[cellDetails objectForKey:#"TableItemTextFontSize"] intValue]];
[cell.contentView addSubview:textLabel];
textLabel.backgroundColor = [UIColor clearColor];
lableHeight = [[cellDetails objectForKey:#"TableItemDetailTextFontSize"] intValue] * 2 + 10;
UILabel *detailTextLabel = nil;
detailTextLabel = [[[UILabel alloc] initWithFrame:CGRectMake(iconSize+10+totalAvailableSpace * 0.8+5, self.tableCellHeight/2 - lableHeight/2, totalAvailableSpace * 0.2 - 10, lableHeight)] autorelease];
detailTextLabel.numberOfLines = 2;
detailTextLabel.lineBreakMode = UILineBreakModeWordWrap;
detailTextLabel.textAlignment = UITextAlignmentLeft;
detailTextLabel.text = [cellDetails objectForKey:#"TableItemDetailText"];
if ([detailTextLableColor scanHexInt:&hex]) {
detailTextLabel.textColor = UIColorFromRGB(hex);
}
detailTextLabel.font = [UIFont fontWithName:[cellDetails objectForKey:#"TableItemDetailTextFontName"] size:[[cellDetails objectForKey:#"TableItemDetailTextFontSize"] intValue]];
[cell.contentView addSubview:detailTextLabel];
detailTextLabel.backgroundColor = [UIColor clearColor];
return cell;
}
Thanks.
That is because toy are adding the views to your cell over and over again.
You should only add them when you create the cell and just set the labels when the cell is being reused.
You could set tags for your label, so that you can set it texts afterwards. The code bellow does the trick
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
if(style == UITableViewCellStyleValue1)
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
else
cell = [[[UITableViewCell alloc] initWithStyle:style reuseIdentifier:CellIdentifier] autorelease];
NSInteger totalAvailableSpace = IPHONE_DISPLAY_WIDTH - iconSize - accesorySize - 10;
NSInteger lableHeight = [[cellDetails objectForKey:#"TableItemTextFontSize"] intValue] * 2 + 10;
UILabel *textLabel = nil;
textLabel.tag = 1;
textLabel = [[[UILabel alloc] initWithFrame:CGRectMake(iconSize+12, self.tableCellHeight/2 - lableHeight/2, totalAvailableSpace * 0.8, lableHeight)] autorelease];
textLabel.numberOfLines = 2;
textLabel.lineBreakMode = UILineBreakModeWordWrap;
textLabel.textAlignment = UITextAlignmentLeft;
textLabel.text = [cellDetails objectForKey:#"TableItemMainText"];
if ([textLableColor scanHexInt:&hex]) {
textLabel.textColor = UIColorFromRGB(hex);
}
textLabel.font = [UIFont fontWithName:[cellDetails objectForKey:#"TableItemTextFontName"] size:[[cellDetails objectForKey:#"TableItemTextFontSize"] intValue]];
[cell.contentView addSubview:textLabel];
textLabel.backgroundColor = [UIColor clearColor];
lableHeight = [[cellDetails objectForKey:#"TableItemDetailTextFontSize"] intValue] * 2 + 10;
UILabel *detailTextLabel = nil;
detailTextLabel.tag = 2;
detailTextLabel = [[[UILabel alloc] initWithFrame:CGRectMake(iconSize+10+totalAvailableSpace * 0.8+5, self.tableCellHeight/2 - lableHeight/2, totalAvailableSpace * 0.2 - 10, lableHeight)] autorelease];
detailTextLabel.numberOfLines = 2;
detailTextLabel.lineBreakMode = UILineBreakModeWordWrap;
detailTextLabel.textAlignment = UITextAlignmentLeft;
detailTextLabel.text = [cellDetails objectForKey:#"TableItemDetailText"];
if ([detailTextLableColor scanHexInt:&hex]) {
detailTextLabel.textColor = UIColorFromRGB(hex);
}
detailTextLabel.font = [UIFont fontWithName:[cellDetails objectForKey:#"TableItemDetailTextFontName"] size:[[cellDetails objectForKey:#"TableItemDetailTextFontSize"] intValue]];
[cell.contentView addSubview:detailTextLabel];
detailTextLabel.backgroundColor = [UIColor clearColor];
} else {
UILabel *textLabel = (UILabel *)[cell viewWithTag:1];
textLabel.text = [cellDetails objectForKey:#"TableItemMainText"];
UILabel *detailTextLabel = (UILabel *)[cell viewWithTag:2];
detailTextLabel.text = [cellDetails objectForKey:#"TableItemDetailText"];
}
return cell;
}
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:nil];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil] autorelease];
}
Make sure that dequeueReusableCellWithIdentifier and reuseIdentifier should be nil
Now it will work !!
Place all the cell UI content inside if(cell==nil){uilabel,uilabel or anythingUI related} ...since ui should be call only once at time of creating cel
To be clear, your problem is that as you scroll a cell into view you will often wind up with the text of the new cell being written over the top of a cell that was just scrolled offscreen?
The problem is that dequeueReusableCellWithIdentifier: doesn't "clean up" the cell (it calls prepareForReuse, but that's it), so all your old subviews are still in place. If you are going to reuse cells, you shouldn't be recreating these subviews each time. Instead, just adjust the properties of the existing subviews on a cell you get back from dequeueReusableCellWithIdentifier:, and only create the new subviews on a newly-allocated cell. Subclassing UITableViewCell can help with this, both to provide properties/ivars in which to hold references to these subviews and to organize the code a little nicer by moving the creation of subviews and the updating into appropriate methods. Or you could just not reuse cells, by passing nil for the reuse identifier.
The most likely reason that it didn't display any content until you scroll up and down is that a newly-created cell may have the framework-provided text field and image view, which may then be removed if the framework determines that you aren't actually using them.
In iOS5 UILineBreakModeWordWrap is deprecated. You should use NSLineBreakByWordWrapping instead.
This would change you code to look like detailTextLabel.lineBreakMode = NSLineBreakByWordWrapping and textLabel.lineBreakMode = NSLineBreakByWordWrapping.
Related
I have created a UITextField in a UITableView. I type the data in and close the keyboard. However when I scroll down and hide the UITextField and then scroll back up again, the 'UITextField' data is duplicated as seen below:
Original Load of View:
Typed in Data:
After hidden textfield and then started editing again:
- (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];
}
if ([indexPath section] == 0) { // Email & Password Section
cell.textLabel.text = #"Subject";
} else {
cell.textLabel.text = #"Task";
}
cell.selectionStyle = UITableViewCellSelectionStyleNone;
if ([indexPath section] == 0) {
UITextField *subject = [[UITextField alloc] initWithFrame:CGRectMake(110, 10, 185, 30)];
subject.adjustsFontSizeToFitWidth = YES;
subject.textColor = [UIColor blackColor];
if ([indexPath row] == 0) {
subject.placeholder = #"Maths";
subject.keyboardType = UIKeyboardTypeEmailAddress;
subject.returnKeyType = UIReturnKeyNext;
}
subject.backgroundColor = [UIColor clearColor];
subject.autocorrectionType = UITextAutocorrectionTypeNo;
subject.autocapitalizationType = UITextAutocapitalizationTypeWords;
subject.tag = 0;
subject.clearButtonMode = UITextFieldViewModeNever;
[cell.contentView addSubview:subject];
} else {
UITextView *task = [[UITextView alloc] initWithFrame:CGRectMake(102, 0, 185, 40)];
task.text = #"fasfashfjasfhasfasdjhasgdgasdhjagshjdgashjdgahjsdghjasgasdashgdgjasd";
task.editable = NO;
task.scrollEnabled = NO;
task.userInteractionEnabled = NO;
task.textColor = [UIColor colorWithRed: 62.0/255.0 green: 85.0/255.0 blue:132.0/255.0 alpha:1.0];
task.backgroundColor = [UIColor clearColor];
}
return cell;
}
Like Richard said, cells are reused (that's what the identifier purpose is), and that's why you test in your tableView:cellForRowAtIndexPath: for a nil value returned by dequeueReusableCellWithIdentifier:.
If a cell already exists (ie. was allocated earlier) and is not displayed anymore, dequeueReusableCellWithIdentifier: will use this cell to display the content of the newly appearing cell.
What you are doing is adding your UITextView every time your cells are displayed and not created. So each time a cell is gets scrolled out of the screen and a new cell pops in, you append a new UITextView in the cell. You should add subviews only in the if (cell == nil) part of your method. As the content of your cells are rather different, I'd recommend using two distinct identifiers.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifierForSection0 = #"Cell0";
static NSString *CellIdentifierForSection1 = #"Cell1";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: [indexPath section] == 0 ? CellIdentifierForSection0 : CellIdentifierForSection1];
if (cell == nil) {
if ([indexPath section] == 0) { // Email & Password Section
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifierForSection0];
cell.textLabel.text = #"Subject";
UITextField *subject = [[UITextField alloc] initWithFrame:CGRectMake(110, 10, 185, 30)];
subject.adjustsFontSizeToFitWidth = YES;
subject.textColor = [UIColor blackColor];
if ([indexPath row] == 0) {
subject.placeholder = #"Maths";
subject.keyboardType = UIKeyboardTypeEmailAddress;
subject.returnKeyType = UIReturnKeyNext;
}
subject.backgroundColor = [UIColor clearColor];
subject.autocorrectionType = UITextAutocorrectionTypeNo;
subject.autocapitalizationType = UITextAutocapitalizationTypeWords;
subject.tag = 0;
subject.clearButtonMode = UITextFieldViewModeNever;
[cell.contentView addSubview:subject];
} else {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifierForSection1];
cell.textLabel.text = #"Task";
UITextView *task = [[UITextView alloc] initWithFrame:CGRectMake(102, 0, 185, 40)];
task.text = #"fasfashfjasfhasfasdjhasgdgasdhjagshjdgashjdgahjsdghjasgasdashgdgjasd";
task.editable = NO;
task.scrollEnabled = NO;
task.userInteractionEnabled = NO;
task.textColor = [UIColor colorWithRed: 62.0/255.0 green: 85.0/255.0 blue:132.0/255.0 alpha:1.0];
task.backgroundColor = [UIColor clearColor];
}
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
return cell;
}
Note that this code is mainly for example purpose, and could be greatly reducted. Moreover, you should use subclass(es) of UITableViewCell like Richard suggested, as it will help organizing your code and make it more reusable.
BUT do NOT use drawRect: to add subviews. This is unnecessary and will impact performances. drawRect: should only be used if you intend to make real drawing like with CoreAnimation or CoreGraphics. Adding subview should be done in initWithFrame: or initWithCoder: depending of your use of Interface Builder or not.
Remember cells get reused, therefore the subviews are added each time it's reused. If you're going to add subviews to a cell you're best off creating a subclass of UITableViewCell and adding the subviews in the drawRect: method of that subclass. That way the modifications are part of the cell and aren't added each time the cell is reused.
I am new to iPhone developer,
I am using UITableView, i want total 6 labels in my Cell of UITableView 3 label on L.H.S and 3 label on R.H.S
Here is my code snippet,
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
return 180;
}
- (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];
CGRect frameL;
frameL.origin.x = 10;
frameL.origin.y = 10;
frameL.size.height = 50;
frameL.size.width = 200;
CGRect frameR;
frameR.origin.x = 200;
frameR.origin.y = 10;
frameR.size.height = 40;
frameR.size.width = 180;
UILabel *AlertNameLHS = [[UILabel alloc] initWithFrame:frameL];
AlertNameLHS.font=[UIFont systemFontOfSize:16.0];
AlertNameLHS.backgroundColor=[UIColor clearColor];
AlertNameLHS.textColor=[UIColor redColor];
AlertNameLHS.text=#"Alert Name :";
[cell.contentView addSubview:AlertNameLHS];
frameL.origin.y += 60;
UILabel *AlertMonthLHS = [[UILabel alloc] initWithFrame:frameL];
AlertMonthLHS.font=[UIFont systemFontOfSize:16.0];
AlertMonthLHS.backgroundColor=[UIColor clearColor];
AlertMonthLHS.textColor=[UIColor redColor];
AlertNameLHS.text=#"Alert Month :";
[cell.contentView addSubview:AlertMonthLHS];
frameL.origin.y += 120;
UILabel *DueOnLHS = [[UILabel alloc] initWithFrame:frameL];
DueOnLHS.font=[UIFont systemFontOfSize:16.0];
AlertNameLHS.text=#"Due On :";
[cell.contentView addSubview:DueOnLHS];
AlertNameRHS = [[UILabel alloc] initWithFrame:frameR];
AlertNameRHS.backgroundColor=[UIColor greenColor];
AlertNameRHS.textColor=[UIColor redColor];
AlertNameRHS.textColor=[UIColor redColor];
AlertNameRHS.font=[UIFont systemFontOfSize:18.0];
[cell.contentView addSubview:AlertNameRHS];
frameL.origin.y += 80;
AlertMonthRHS = [[UILabel alloc] initWithFrame:frameR];
AlertMonthRHS.font=[UIFont systemFontOfSize:18.0];
[cell.contentView addSubview:AlertMonthRHS];
frameL.origin.y += 120;
DueOnRHS = [[UILabel alloc] initWithFrame:frameR];
DueOnRHS.font=[UIFont systemFontOfSize:18.0];
[cell.contentView addSubview:DueOnRHS];
}
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
AlertNameRHS.text = [Myarray objectAtIndex:indexPath.row];
return cell;
}
but i am unable to see my UILabel properly.
Any help will be appreciated.
EDIT: :
See the corrected code:
- (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];
CGRect frameL;
frameL.origin.x = 10;
frameL.origin.y = 10;
frameL.size.height = 50;
frameL.size.width = 200;
CGRect frameR;
frameR.origin.x = 200;
frameR.origin.y = 10;
frameR.size.height = 40;
frameR.size.width = 180;
UILabel *AlertNameLHS = [[UILabel alloc] initWithFrame:frameL];
AlertNameLHS.font=[UIFont systemFontOfSize:16.0];
AlertNameLHS.backgroundColor=[UIColor clearColor];
AlertNameLHS.textColor=[UIColor redColor];
AlertNameLHS.text=#"Alert Name :";
[cell.contentView addSubview:AlertNameLHS];
frameL.origin.y += 60;
NSLog(#"fr %f", frameL.origin.y);
UILabel *AlertMonthLHS = [[UILabel alloc] initWithFrame:frameL];
AlertMonthLHS.font=[UIFont systemFontOfSize:16.0];
AlertMonthLHS.backgroundColor=[UIColor clearColor];
AlertMonthLHS.textColor=[UIColor redColor];
AlertMonthLHS.text=#"Alert Month :";
[cell.contentView addSubview:AlertMonthLHS];
frameL.origin.y += 60;
NSLog(#"fr %f", frameL.origin.y);
UILabel *DueOnLHS = [[UILabel alloc] initWithFrame:frameL];
DueOnLHS.font=[UIFont systemFontOfSize:16.0];
DueOnLHS.text=#"Due On :";
[cell.contentView addSubview:DueOnLHS];
AlertNameRHS = [[UILabel alloc] initWithFrame:frameR];
AlertNameRHS.backgroundColor=[UIColor greenColor];
AlertNameRHS.textColor=[UIColor redColor];
AlertNameRHS.textColor=[UIColor redColor];
AlertNameRHS.font=[UIFont systemFontOfSize:18.0];
AlertNameRHS.text = #"l1";
[cell.contentView addSubview:AlertNameRHS];
frameR.origin.y += 60;
AlertMonthRHS = [[UILabel alloc] initWithFrame:frameR];
AlertMonthRHS.font=[UIFont systemFontOfSize:18.0];
AlertMonthRHS.text =#"l2";
[cell.contentView addSubview:AlertMonthRHS];
frameR.origin.y += 60;
DueOnRHS = [[UILabel alloc] initWithFrame:frameR];
DueOnRHS.font=[UIFont systemFontOfSize:18.0];
DueOnRHS.text = #"l3";
[cell.contentView addSubview:DueOnRHS];
}
cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
AlertNameRHS.text = [NSString stringWithFormat:#"%d",indexPath.row];
return cell;
}
You've made too many mistakes:
The LHS1 is visible, but you override it's text with LHS3 text: AlertNameLHS.text=#"Due On :";
The LHS2 isn't visible because you only initialize it and add as a subview, configured LHS1 instead of it
The LHS3 is not visible because the cell height is 180 and it's y coordinate is 190, you also don't set it's text setting the LHS1 text instead.
The RHS labels frames are incorrect and out of cell frame, you are supposed to use frameR but using frameL, i also suggest you want to add 60 pixels to y coordinate on every step.
To perform this kind of work, I would suggest you to create one custom cell . (Add New file -> Objective-C class -> UItableViewCell)
Define 6 Lables with property
#import <UIKit/UIKit.h>
#interface DemoCell : UITableViewCell
{
IBOutlet UILabel *lblOne;
}
#property (nonatomic,retain) IBOutlet UILabel *lblOne;
Now Create a new Empty View (Only nib file) name it Democell (for your convenience)
Now in that Delete the view from nib file and from the Library drag and Drop a Table View Cell at the place of your View in nib file.
Now select your tableviewcell , and in its identity inspector , change its class to DemoCell
So This will link your nib file with custom cell class..
Now in the nib file ,drag&drop 6 label, position them as per your requirement , and in the file owner link all the lbls with lblOne,lblTwo ,,,,....
Now your custom cell is complete.
To use this cell in your table's cellforrowatindexpath
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"cell";
DemoCell *cell= (DemoCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell ==nil)
{
cell=[[[NSBundle mainBundle]loadNibNamed:#"DemoCell" owner:self options:nil] lastObject];
}
cell.lblone.textlabel.text = #"lblOne";
Define 6 labels and set frames for that.
Then, addSubView to the tableViewCell contentView.
I have a UITableView with regular UITableViewCell, but I don't use any of UITableViewCell's lables. I just use the cell to embed a label and a UITextField to input some data. Problem is when you scroll up or scroll down and the UITableviewCell redraws itself, it draws an overlapping UITextFieldView over the old one and you see doubles! I'm thinking that maybe since I do put these UITextFields into a dictionary, it might save the textfield with a strong pointer, and try to make another one and just overlap. Anyone have any suggestions?
Here is my code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"ProductCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
NSDictionary *product = [self.products objectAtIndex:indexPath.row];
NSDictionary *orderpoint = [self.orderpoints objectAtIndex:indexPath.row];
cell.textLabel.text = #""; //black out text
CGFloat calculatedHeight = [self tableView:tableView heightForRowAtIndexPath:indexPath];
UILabel *productLabel = [[UILabel alloc] initWithFrame:CGRectMake(0.0, 0.0, cell.bounds.size.width - 50.0, calculatedHeight)];
productLabel.text = [[NSString alloc] initWithFormat:#"%#. %#",
[orderpoint objectForKey:#"sequence_nr"], [product objectForKey:#"name"]];
//word wrapping
productLabel.lineBreakMode = UILineBreakModeWordWrap;
productLabel.numberOfLines = 0; //infinite number of lines
productLabel.font = [UIFont fontWithName:#"Helvetica" size:14.0];
[cell.contentView addSubview:productLabel];
//create the cell's textfield
UITextField *cellTextField = [[UITextField alloc] initWithFrame:CGRectMake(cell.bounds.size.width - 50, cell.bounds.size.height - 30, 50, calculatedHeight - 20)];
cellTextField.adjustsFontSizeToFitWidth = YES;
cellTextField.textColor = [UIColor blackColor];
cellTextField.keyboardType = UIKeyboardTypeNumberPad; // will only need to end a count
cellTextField.returnKeyType = UIReturnKeyDone; // TODO make it go to the next items key, or make it exit out
cellTextField.backgroundColor = [UIColor whiteColor];
cellTextField.textAlignment = UITextAlignmentLeft; //align to the right
//cellTextField.delegate = self; //will need to set delegate, maybe
cellTextField.clearButtonMode = UITextFieldViewModeNever;
cellTextField.enabled = YES;
cellTextField.borderStyle = UITextBorderStyleRoundedRect; //add bezel rounded look to textfield
cellTextField.delegate = self;
[cell.contentView addSubview: cellTextField]; //add the textfield to the cell
// save to dictionary, using a dictionary because not certain if this is created in order to use an Array
[self.textFieldDict setObject:cellTextField forKey:[[NSNumber alloc] initWithInteger:indexPath.row]];
return cell;
}
You have not initialized your cell.Try this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"ProductCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
//It will check whether cell in there or not, then deque the cell...
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
NSDictionary *product = [self.products objectAtIndex:indexPath.row];
NSDictionary *orderpoint = [self.orderpoints objectAtIndex:indexPath.row];
cell.textLabel.text = #""; //black out text
CGFloat calculatedHeight = [self tableView:tableView heightForRowAtIndexPath:indexPath];
UILabel *productLabel = [[UILabel alloc] initWithFrame:CGRectMake(0.0, 0.0, cell.bounds.size.width - 50.0, calculatedHeight)];
productLabel.text = [[NSString alloc] initWithFormat:#"%#. %#",
[orderpoint objectForKey:#"sequence_nr"], [product objectForKey:#"name"]];
//word wrapping
productLabel.lineBreakMode = UILineBreakModeWordWrap;
productLabel.numberOfLines = 0; //infinite number of lines
productLabel.font = [UIFont fontWithName:#"Helvetica" size:14.0];
[cell.contentView addSubview:productLabel];
//create the cell's textfield
UITextField *cellTextField = [[UITextField alloc] initWithFrame:CGRectMake(cell.bounds.size.width - 50, cell.bounds.size.height - 30, 50, calculatedHeight - 20)];
cellTextField.adjustsFontSizeToFitWidth = YES;
cellTextField.textColor = [UIColor blackColor];
cellTextField.keyboardType = UIKeyboardTypeNumberPad; // will only need to end a count
cellTextField.returnKeyType = UIReturnKeyDone; // TODO make it go to the next items key, or make it exit out
cellTextField.backgroundColor = [UIColor whiteColor];
cellTextField.textAlignment = UITextAlignmentLeft; //align to the right
//cellTextField.delegate = self; //will need to set delegate, maybe
cellTextField.clearButtonMode = UITextFieldViewModeNever;
cellTextField.enabled = YES;
cellTextField.borderStyle = UITextBorderStyleRoundedRect; //add bezel rounded look to textfield
cellTextField.delegate = self;
[cell.contentView addSubview: cellTextField]; //add the textfield to the cell
return cell;
}
Either don't use reusability and always alloc the cell at each time or
make a check after dequeue (like this)
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell==nil)
{
// make text field and label an add tag
}
//and outside this by using tag fetch the labels and textField and clear the textFields.
You forgot to put the condition like this:
if (cell == nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefaultreuseIdentifier:CellIdentifier];
}
Used this as a reference: add subviews to UITableViewCell
I just first checked to see if this view was added from before, and if it was, then don't add it again. It has nothing to do with the cell being nil. Unless I missed something? all I know is that this seems to be working fine, now.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"ProductCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
NSDictionary *product = [self.products objectAtIndex:indexPath.row];
NSDictionary *orderpoint = [self.orderpoints objectAtIndex:indexPath.row];
cell.textLabel.text = #""; //black out text
CGFloat calculatedHeight = [self tableView:tableView heightForRowAtIndexPath:indexPath];
UILabel *productLabel = [[UILabel alloc] initWithFrame:CGRectMake(0.0, 0.0, cell.bounds.size.width - 50.0, calculatedHeight)];
productLabel.text = [[NSString alloc] initWithFormat:#"%#. %#",
[orderpoint objectForKey:#"sequence_nr"], [product objectForKey:#"name"]];
//word wrapping
productLabel.lineBreakMode = UILineBreakModeWordWrap;
productLabel.numberOfLines = 0; //infinite number of lines
productLabel.font = [UIFont fontWithName:#"Helvetica" size:14.0];
[cell.contentView addSubview:productLabel];
if (![cell viewWithTag:1])
{
//create the cell's textfield
UITextField *cellTextField = [[UITextField alloc] initWithFrame:CGRectMake(cell.bounds.size.width - 50, cell.bounds.size.height - 30, 50, calculatedHeight - 20)];
cellTextField.adjustsFontSizeToFitWidth = YES;
cellTextField.textColor = [UIColor blackColor];
cellTextField.keyboardType = UIKeyboardTypeNumberPad; // will only need to end a count
cellTextField.returnKeyType = UIReturnKeyDone; // TODO make it go to the next items key, or make it exit out
cellTextField.backgroundColor = [UIColor whiteColor];
cellTextField.textAlignment = UITextAlignmentLeft; //align to the right
cellTextField.delegate = self; //will need to set delegate, maybe
cellTextField.clearButtonMode = UITextFieldViewModeNever;
cellTextField.enabled = YES;
cellTextField.borderStyle = UITextBorderStyleRoundedRect; //add bezel rounded look to textfield
cellTextField.delegate = self;
cellTextField.tag = 1; //set tag to 1
[cell.contentView addSubview: cellTextField]; //add the textfield to the cell
// save to dictionary, using a dictionary because not certain if this is created in order to use an Array
[self.textFieldDict setObject:cellTextField forKey:[[NSNumber alloc] initWithInteger:indexPath.row]];
}
return cell;
}
I put multiple UILabels inside every cell in a UITableView instead of a single cell.textLabel.text. I then use reloaddata to put new uilabels. How do i get rid of the old labels ?
edit: If i put 5 labels in a cell then reload the cell using only 2 labels, there are 3 more labels left over from the last time i called cellForRowAtIndexPath.
If i use viewWithTag like Goldeen said, i can reuse old labels but can i remove labels i dont want from memory ?
edit:
this is my method
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
MyTableCell *cell = (MyTableCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[MyTableCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
UILabel *label = [[[UILabel alloc] initWithFrame:CGRectMake(j*50.0, 0, 49.0,logicTable.rowHeight)] autorelease];
label.tag = 1;
label.text = [NSString stringWithFormat:#"ABC"];
label.textAlignment = UITextAlignmentCenter;
label.autoresizingMask = UIViewAutoresizingFlexibleRightMargin |
UIViewAutoresizingFlexibleHeight;
[cell.contentView addSubview:label];
return cell;
}
What it sounds like you are doing is, in your cellForRowAtIndexPath method, you are setting up your UITableViewCells with some labels in them and each time, you are making the labels from scratch. What you should be doing is, setting up the labels if you are making a new cell, and then setting the values on the labels outside of this to fully utilize the ability to reuse table view cells to improve performance of scrolling the table view.
The key method is -viewWithTag: which, along with the tag property on UIView you can use to find a specific subview.
A little sample code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"MyCellIdentifier";
UITableViewCell *cell = (WHArticleTableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
UILabel *firstLabel = nil;
UILabel *secondLabel = nil;
UILabel *thirdLabel = nil;
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
firstLabel = [[[UILabel alloc] initWithFrame: CGRectMake(0.0, 0.0, 20.0, 20.0)] autorelease];
firstLabel.tag = 1;
[cell addSubview:firstLabel];
secondLabel = [[[UILabel alloc] initWithFrame: CGRectMake(20.0, 0.0, 20.0, 20.0)] autorelease];
secondLabel.tag = 2;
[cell addSubview:secondLabel];
thirdLabel = [[[UILabel alloc] initWithFrame: CGRectMake(40.0, 0.0, 20.0, 20.0)] autorelease];
thirdLabel.tag = 3;
[cell addSubview:thirdLabel];
}
else
{
firstLabel = (UILabel *)[cell viewWithTag:1];
secondLabel = (UILabel *)[cell viewWithTag:2];
thirdLabel = (UILabel *)[cell viewWithTag:3];
}
firstLabel.text = #"First Label's Text Here";
secondLabel.text = #"Second Label's Text Here";
thirdLabel.text = #"Third Label's Text Here";
return cell;
}
I have found some posts which are similar to my issue but not quite the same.
In my app the user can navigate between several uitableviews to drill down to the desired result. When a user goes forward, then backward, then forward, etc it is noticeable that the rows are being redrawn/re-written and the text gets bolder and bolder.
I have found that in some of the posts this may relate to the way that I am creating the rows, using a uilable within the cellforrowatindexpath method.
Is there something that I need to do so that the rows are not repopulate/redrawn each time a user goes forward and backward between the tableviews? Do I need to add something to the code below or add something to the viewwillappear method (currently there is a 'reloaddata' in the viewwillappear for the table but doesn't seem to help)?
Here is my code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
}
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
UILabel *label = [[[UILabel alloc] init] autorelease];
label.font = [UIFont fontWithName:#"Arial-BoldMT" size:20];
label.frame = CGRectMake(10.0f, 10.0f, 220.0f, 22.0f);
label.textColor = [UIColor blackColor];
label.backgroundColor = [UIColor clearColor];
label.opaque = NO;
label.text = [mapareaArray objectAtIndex:indexPath.row];
[cell.contentView addSubview:label];
CustomCellBackgroundView *bgView = [[CustomCellBackgroundView alloc] initWithFrame:CGRectZero];
bgView.borderColor = [UIColor clearColor];
bgView.fillColor = [UIColor whiteColor];
bgView.position = CustomCellBackgroundViewPositionSingle;
cell.backgroundView = bgView;
return cell;
}
The problem you are having is due to this line:
[cell.contentView addSubview:label];
You are adding a subview to the table cell whether it's a new cell or not. If it's an old cell (dequeued from the reusable pool), then you will add yet another subview to the cell.
Instead, you should tag the UILabel, and then locate it with the tag to modify the content of that UILabel. Add (and set all of its attributes) and tag the UILabel inside the if( cell == nil ) block:
if(cell == nil) {
// alloc and init the cell view...
UILabel *label = [[[UILabel alloc] init] autorelease];
label.tag = kMyTag; // define kMyTag in your header file using #define
// and other label customizations
[cell.contentView addSubview:label]; // addSubview here and only here
...
}
Then locate it with:
UILabel *label = (UILabel *)[cell.contentView viewWithTag: kMyTag];
label.text = [mapareaArray objectAtIndex:indexPath.row];
And no need to re-add it as a subview outside of the if(cell == nil) block. The subview is already there (and that's why reusing the cell views are so much more efficient, if you do it correctly, that is ;).
.h file
The 'define' is put after the #import statements at top of header file, and was put as 0 because I don't know how else to define it:
#define kMyTag 0
.m file
I have updated this section as per your comments, but a) the table is not populated, b) when the user has navigated to the next view and goes back to this view it fails with a "unrecognized selector sent to instance", and c) I had to put in the two 'return cell;' entries or it falls over. I think I have things in the wrong order and maybe didn't initialise things properly????
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
UILabel *label = [[[UILabel alloc] init] autorelease];
label.tag = kMyTag; // define kMyTag in your header file using #define
label.font = [UIFont fontWithName:#"Arial-BoldMT" size:20];
label.frame = CGRectMake(10.0f, 10.0f, 220.0f, 22.0f);
label.textColor = [UIColor blackColor];
label.backgroundColor = [UIColor clearColor];
label.opaque = NO;
CustomCellBackgroundView *bgView = [[CustomCellBackgroundView alloc] initWithFrame:CGRectZero];
bgView.borderColor = [UIColor clearColor];
bgView.fillColor = [UIColor whiteColor];
bgView.position = CustomCellBackgroundViewPositionSingle;
cell.backgroundView = bgView;
[cell.contentView addSubview:label]; // addSubview here and only here
return cell;
}
UILabel *label = (UILabel *)[cell.contentView viewWithTag: kMyTag];
label.text = [mapareaArray objectAtIndex:indexPath.row];
return cell;
}
You should create a subclass for UITableViewCell for that specific cell, then apply the logic to see if you need to add the subview to itself every time. Also, use the UITableviewcell's prepareForReuse and remove any subviews during that time before applying the logic of wether you want to add a UILabel to your Cell.