Into the cellForRowAtIndexPath: method of an UITableViewController class I am using the next code to show a cell that contains an UITextView.
Sometimes when I scroll the table that contains the cell and then I scroll the cell UITextView, it shows the cell text reprinted (as if there were two UITextView objects, instead of one, into the cell).
What can I do to solve this problem?
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
cell.contentView.bounds = CGRectMake(0, 0, cell.frame.size.width, cell.frame.size.height);
cell.selectionStyle = UITableViewCellSelectionStyleNone;
UITextView *textView = [[UITextView alloc] initWithFrame:cell.contentView.bounds];
textView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
textView.editable = NO;
textView.scrollEnabled = YES;
textView.backgroundColor = [UIColor clearColor];
textView.font = [UIFont fontWithName:#"Helvetica" size:14.0];
textView.text = self.description;
[cell.contentView addSubview:textView];
[textView release];
UITableView reuses its cells to increase scrolling performance. Whenever a cell is being reused, you are adding a new text view to the cell (although one is already there).
You should move the creation of the text view (and adding it to the cell) into the if (cell == nil) block. Inside this block, also give the text view a unique tag and use this tag property to access the text view from outside the block. See Apple's table view sample code for examples of this pattern, it is being used a lot.
Related
If I have a long text I have to increase the cell size to fit the text.
When I assign: cell.textLabel.text = #"my string" , if the string is long it gets truncated.
How can I display the text in two or more rows for this case? I am using UITableViewCell only and not subclassing it anywhere. Is there some code to display long texts using cell.textLabel directly? I am not talking about adding a seperate view to cell.
cell.textLabel will not allow you to line break a string into two lines. What you will have to do is customize it add your own UILabel to UITableViewCell and define its parameters.
Here's a working code that you can add to your TableView.
//define labelValue1 in your .h file
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//NSLog(#"Inside cellForRowAtIndexPath");
static NSString *CellIdentifier = #"Cell";
// Try to retrieve from the table view a now-unused cell with the given identifier.
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// If no cell is available, create a new one using the given identifier.
if (cell == nil)
{
// Use the default cell style.
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
labelValue1 = [[UILabel alloc] initWithFrame:CGRectMake(10, 10, 200, 100)]; //adjust label size and position as needed
labelValue1.font = [UIFont fontWithName:#"BradleyHandITCTT-Bold" size: 23.0];
labelValue1.textColor = [UIColor whiteColor];
labelValue1.textAlignment = NSTextAlignmentCenter;
labelValue1.numberOfLines = 2; //note: I said number of lines need to be 2
labelValue1.backgroundColor = [UIColor clearColor];
labelValue1.adjustsFontSizeToFitWidth = YES;
labelValue1.tag = 100;
[cell.contentView addSubview:labelValue1];
}
else
{
labelValue1 = (UILabel *) [cell viewWithTag:100];
}
// Set up the cell.
NSString *str1 = [arryData3 objectAtIndex:indexPath.row];
labelValue1.text = str1;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
Multiple lines can be shown using
cell.textLabel.LineBreakMode = NSLineBreakByWordWrapping
This is for Swift.
cell.textLabel?.numberOfLines = 10 /// or the number you like.
As I scroll up and down the table view the data in each cell becomes duplicated and unreadable. Does anyone have any suggestions for the below?
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateStyle:NSDateFormatterShortStyle];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
UILabel *label1 = [[UILabel alloc]initWithFrame:CGRectMake(10, 12, 250, 20)];
UILabel *label2 = [[UILabel alloc]initWithFrame:CGRectMake(250, 12, 50, 20)];
label1.tag= 666;
label2.tag= 666;
[cell.contentView addSubview:label1];
[cell.contentView addSubview:label2];
// Configure the cell...
President *p = (President *)[self.importedRows objectAtIndex:indexPath.row];
label1.text = p.no;
label2.text = p.name;
UILabel* cellLabel = (UILabel*)[cell viewWithTag: 666];
cellLabel.text = [NSString stringWithFormat:p.no , p.name];
return cell;
}
dequeueReusableCellWithIdentifier caches the generated cells. So if you request a cell which you already created before this cell will NOT be generated again from scratch (meaning that the labels you added before already exists!).
So when adding the labels tag them with a unique number :
label1.tag= 666;
label2.tag= 667;
And before adding them to the cell remove them as follows :
UIView *labelView = [cell.contentView viewForTag:666];
if (labelView != nil) {
[labelView removeFromSuperView];
}
And do the same with the second label.
because you are adding label1 and label2 again and again to cell.
UILabel *label1 = [[UILabel alloc]initWithFrame:CGRectMake(10, 12, 250, 20)];
UILabel *label2 = [[UILabel alloc]initWithFrame:CGRectMake(250, 12, 50, 20)];
[cell.contentView addSubview:label1];
[cell.contentView addSubview:label2];
As the cell is reused, same cell is used for another row, and it already has label1,2. but you are creating label1,2 again and again and adding them to it.
Give different tags for label1,label2.Check if viewWithTag:666 and 667 is present.If not present add them as subview ,if already present, just get them using viewWithTag and change their text values.
The problem here is with below code:
UILabel* cellLabel = (UILabel*)[cell viewWithTag: 666];
cellLabel.text = [NSString stringWithFormat:p.no , p.name];
I have tried your code, commenting these two lines stop overlapping. You can try to change the frame of this label.
I suggest making your own subclass of UITableViewCell which has two UILabel's on it, then in the method you're using above, create instances of your subclass rather than UITableViewCell if the cell doesn't exist, then populate the labels.
In your custom cell implementation file, you'll have to override the 'prepareForReuse' method, and in it set the text of your labels to nil (#""). This properly uses the 'dequeueWithReuseIdentifier' functionality and only creates the labels when necessary, rather than only showing them when required.
A solution where you can gain performance is the following.
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
// create and add labels to the contentView
}
// retrieve and update the labels
Obviously you could also create your UITableViewCell subclass.
You could also try this swag (fresh answer, get your fresh answer!):
BOOL doesContain = [cell.subviews containsObject:imageView];
if (!doesContain)
{
[cell.contentView addSubview:imageView];
}
imageView.image = yourImage];
Also for a quick way to subclass all of your stuff, check my answer.
I have a simple tableView with 20 rows. I created a subclass custom UITableview cell, and in cellforRowAtIndex, I add a textfield to the cell once every other 3 rows. When I scroll up and down text fields show up in the wrong rows. Note, I can't make UItextfield part of my custom cell, because this can be anything, checkbox, radio button, but for simplicity I chose UITextfield... What am I doing wrong?
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"TestCellIdentifier";
testCell *cell = (testCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if(!cell)
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
else{
//HMMM I also tried removing it before adding it- it doesn't work neither
for(UIView *v in cell.subviews){
if(v.tag == 999 ){
[v removeFromSuperview];
}
}
//add UItextField to row if it's divisible by 3
if(indexPath.row %3 ==0){
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(400, 10, 300, 30)];
textField.borderStyle = UITextBorderStyleRoundedRect;
textField.font = [UIFont systemFontOfSize:15];
textField.placeholder = [NSString stringWithFormat:#"%d",indexPath.row];
textField.autocorrectionType = UITextAutocorrectionTypeNo;
textField.keyboardType = UIKeyboardTypeDefault;
textField.returnKeyType = UIReturnKeyDone;
textField.clearButtonMode = UITextFieldViewModeWhileEditing;
textField.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
textField.tag = 999;
[cell addSubview:textField];
}
}
cell.textLabel.text = [NSString stringWithFormat:#"%d",indexPath.row];
return cell;
}
don't use the Reusability ?
in this scene,i will not use the reusability
Reusing cells is a good thing and you should be able to do it.
You could consider removing the text field from the cell when it goes offscreen, before it is queued for reuse, in the delegate protocol method:
– tableView:didEndDisplayingCell:forRowAtIndexPath:
Knowing the row number you would know whether or not to remove the textfield.
Edited to add explanation:
On first glance your code looks OK, so I did a little test project.
The problem with your original code is that you're adding the textfield to the wrong "view" -- UITableViewCells have some structure that you need to pay attention to. Look at the documentation for the UITableViewCell contentView property. It says, in part:
If you want to customize cells by simply adding additional views, you
should add them to the content view so they will be positioned
appropriately as the cell transitions into and out of editing mode.
So the code should add to and enumerate subviews of the cell's contentView:
for(UIView *v in cell.contentView.subviews){
if(v.tag == 999 ){
[v removeFromSuperview];
}
}
...
textField.tag = 999;
[cell.contentView addSubview:textField];
My table view has inline cells adding.
I've got in cellForRowAtIndexPath:
VMEditableTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"EditableCell"];
cell.editableTF.font = [UIFont fontWithName:#"Helvetica" size:17.0];
cell.editableTF.delegate = self;
cell.editableTF.tag = indexPath.row;
[cell.editableTF setBorderStyle:UITextBorderStyleNone];
if ([self.extrasArray[indexPath.row] isEqual:#0]) { // recognise new added cell
self.extrasArray[indexPath.row] = #"";
[cell.editableTF becomeFirstResponder];
}
cell.editableTF.text = self.extrasArray[indexPath.row];
return cell;
When i start table view - inline adding works fine.
The problem starts when i use "clear whole list" button - which simply removes all objects from extrasArray.
When I add cell after clearing it's being dequeued improperly and the textfield doesnt respond to becomeFirstResponder.
(it's not nil, it calls textFieldShouldBeginEditing(always YES) but nothing more happens - no keyboard is showing up.
My last idea was to to override prepareForReuse method inside of Cell Implementation - but sadly neither setting editableTF to nil and reinitalizing it doesnt work.
How can I force cell to recreate itself instead of coping?
Try to create a cell like this
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:nil];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
// Set up the cell..
[self configureCell:cell atIndexPath:indexPath];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
'
So todays morning was very good for code soultions and finally I came up with one for this problem:
I got rid of storyboard for this cell and changed all pointers of custom cell to strong (so I own them).
Dequeque reusable cell was recreating UITextField from deleted rows making controller confused about ownership and becoming first responder.
be aware that creating them inside of cell init didn't do the trick.
TextField MUST be created and added as subview (also assigned to strong pointer so I get control over it later).
Here is some code:
VMEditableTableViewCell *cell = [[VMEditableTableViewCell alloc] init];
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
UIImage *bulletImage = [UIImage imageNamed:#"common_ico_dot.png"];
UIImageView *bulletImageView = [[UIImageView alloc] initWithFrame:CGRectMake(20,17,10, 10)];
bulletImageView.image = bulletImage;
UIImage *tickImage = [UIImage imageNamed:#"common_green_tick.png"];
UIImageView *tickImageView = [[UIImageView alloc] initWithFrame:CGRectMake(cell.bounds.size.width-30, 17, tickImage.size.width, tickImage.size.height)];
tickImageView.image = tickImage;
tickImageView.hidden = YES;
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(60, 10, 227, 30)];
textField.autocorrectionType = UITextAutocorrectionTypeNo;
textField.autocapitalizationType = UITextAutocapitalizationTypeNone;
textField.delegate = self;
textField.font = [UIFont fontWithName:#"Maven Pro" size:17.0];
textField.tag = indexPath.row;
[textField setBorderStyle:UITextBorderStyleNone];
[cell addSubview:bulletImageView];
cell.bulletImageView = bulletImageView;
[cell addSubview:tickImageView];
cell.tickImageView = tickImageView;
if (cell.editableTF == nil) {
[cell addSubview:textField];
cell.editableTF = textField;
}
Im adding 2 texts into a cell of a table. What I am doing is
UITableViewCell *cell =nil;
NSString *CellIdentifier = #"Cell";
cell = [aTableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
[[UILabel alloc] initWithFrame:CGRectMake(80.0, 0.0, 220.0, 10.0)];
mainLabel.tag = 1003;
mainLabel.text = #"Text 1";
mainLabel.textAlignment = UITextAlignmentLeft;
mainLabel.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin|
UIViewAutoresizingFlexibleHeight;
[cell.contentView addSubview:mainLabel];
}
I do the same thing to add secondLabel to a cell.
What is displaying on the simulator is
Now the problem is the background of 2 UILabel is not the same with the background of the cell ( my cells are grouped in the table view )
Does anyone know how to fix this problem.
Any comments are welcomed here
Thanks
If I have understand well the question, you need to delete the UILabel background because you want to show the UITableViewCell background instead. So I think you only have to do that:
mainLabel.backgroundColor = [UIColor clearColor];
Like the answer above, you should set the same color for both of the view.
cell.backgroundColor = [UIColor clearColor];
or you can set the color of the View you set.