my problem is I want to add custom designed seperator line between my UITableview cells except first cell of table(indexPath.row=0). Following code seems fine when I reload my table first time. However when I scroll down and scroll up it appears custom seperator line on the top of the first cell of table. I printed indexpath.row value and discovered that if I scrolls up first cell of table is reconstructed at indexpath.row=7. Any solution? Thanks for reply :) My code is:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"CustomCellIdentifier";
CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = (CustomCell *)[CustomCell cellFromNibNamed:#"CustomTwitterCell"];
}
if(indexPath.row!=0)
{
UIView *lineView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 2.5)];
lineView.backgroundColor = [[UIColor alloc] initWithPatternImage:[UIImage imageNamed:#"line.png"]];
[cell.contentView addSubview:lineView];
[lineView release];
}
NSDictionary *tweet;
tweet= [twitterTableArray objectAtIndex:indexPath.row];
cell.twitterTextLabel.text=[tweet objectForKey:#"text"];
cell.customSubLabel.text=[NSString stringWithFormat:#"%d",indexpath.row];
}
That because the table uses a reused cell that was build with the separator line, you can use two CellIdentifier one for your first row, and another for all the rest..
Try something like (didn't test the code but it should work):
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *FirstCellIdentifier = #"FirstCellIdentifier";
static NSString *OthersCellIdentifier = #"OthersCellIdentifier";
NSString *cellIndentitier = indexPath.row == 0 ? FirstCellIdentifier : OthersCellIdentifier;
CustomCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIndentitier];
if (cell == nil) {
cell = (CustomCell *)[CustomCell cellFromNibNamed:cellIndentitier];
if(indexPath.row!=0) {
UIView *lineView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 2.5)];
lineView.backgroundColor = [[UIColor alloc] initWithPatternImage:[UIImage imageNamed:#"line.png"]];
[cell.contentView addSubview:lineView];
[lineView release];
}
}
NSDictionary *tweet;
NSDictionary *tweet= [twitterTableArray objectAtIndex:indexPath.row];
cell.twitterTextLabel.text = [tweet objectForKey:#"text"];
cell.customSubLabel.text = [NSString stringWithFormat:#"%d",indexpath.row];
}
Related
I have custom cell in my UITableView and according to the string's value I want to add a UILabel in the cell.
Here is my code for cell,
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSDictionary * tmpDictn = [tableAry objectAtIndex:indexPath.section];
NSString * typeStr = [tmpDictn objectForKey:#“DocumentType”];
NSString * cellIdentifier = #"TestCell";
TestCell *cell = (TestCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (!cell){
cell = [[TestCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
if ([typeStr isEqualToString:#“Text”]) {
UILabel * textLbl = [[UILabel alloc] init];
textLbl.backgroundColor=[UIColor clearColor];
textLbl.textColor=[UIColor lightGrayColor];
textLbl.userInteractionEnabled=NO;
textLbl.numberOfLines = 0;
textLbl.font = [UIFont fontWithName:#“Helvetica" size:16];
[textLbl setFrame:CGRectMake(30, 20, 250, 25)];
textLbl.text= [NSString stringWithFormat:#"%# %i",[splitAry objectAtIndex:i],indexPath.section];
[cell addSubview:textLbl];
}
}
return cell;
}
My UITableView contain 5 cell(dynamic). And only first cell should have this label(this also change according to Text). This code is adding UILabel in first cell but also add UILabel at 3 and 5th cell.
I have checked that its same UILabel created 1 time and added in cell 1st, 3rd and 5th. And "Text" is only at first position in Tableary.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSDictionary * tmpDictn = [tableAry objectAtIndex:indexPath.section];
NSString * typeStr = [tmpDictn objectForKey:#“DocumentType”];
NSString * cellIdentifier = #"TestCell";
TestCell *cell = (TestCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (!cell){
cell = [[TestCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
UILabel *lbl = [cell viewWithTag:1];
if(lbl)
{
[lbl removeFromSuperView];
}
if ([typeStr isEqualToString:#“Text”]) {
UILabel * textLbl = [[UILabel alloc] init];
textLabel.tag = 1;
textLbl.backgroundColor=[UIColor clearColor];
textLbl.textColor=[UIColor lightGrayColor];
textLbl.userInteractionEnabled=NO;
textLbl.numberOfLines = 0;
textLbl.font = [UIFont fontWithName:#“Helvetica" size:16];
[textLbl setFrame:CGRectMake(30, 20, 250, 25)];
textLbl.text= [NSString stringWithFormat:#"%# %i",[splitAry objectAtIndex:i],indexPath.section];
[cell addSubview:textLbl];
}
}
return cell;
}
Try using a different cell identifier for the cells that need a label added to them, e.g. #"TextCell". Otherwise, you are reusing cells that already have a label added even if it is not supposed to be there. Alternatively, you could remove the label (if it is there) in an 'else' condition of your if ([typeStr isEqualToString:#“Text”]) block but I think that the former is cleaner.
You are using
[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
The problem for your code is that table view is reusing your cell. So it will appear in many as your number of cells increases.
I am a bit old programmer but I think the best way is to
if (!cell)
{
cell = [[TestCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
//Add your label here.
}
if(!label)
{ //your code;
//set label text to nil if your condition not met;
}
A quick solution for you is to put an else and set text to nil;
Cheers.
I have some trouble with adding UILabel as subview to UITableViewCell. My code:
bookMarkTable=[[UITableView alloc]initWithFrame:CGRectMake(0, 50, 480, 270)];
bookMarkTable.rowHeight = 38.0f;
bookMarkTable.backgroundColor=[UIColor colorWithRed:247/255.0 green:246/255.0 blue:242/255.0 alpha:1];
[bookMarkTable setDelegate:self];
[bookMarkTable setDataSource:self];
[bookMarkMainView addSubview:bookMarkTable];
and UITableView delegate methods:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return bookMarksArray.count;
}
- (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];
}
// Configure the cell...
NSMutableDictionary* cellDictionary =[bookMarksArray objectAtIndex:indexPath.row];
UILabel* bookMarkTitle =[[UILabel alloc]initWithFrame:CGRectMake(50, 0, 370, 40)];
bookMarkTitle.text=[cellDictionary valueForKey:#"bm_title"];
bookMarkTitle.backgroundColor=[UIColor clearColor];
bookMarkTitle.font=[UIFont fontWithName:#"Georgia" size:20.0f];
[cell.contentView addSubview:bookMarkTitle];
return cell;
}
- (CGFloat) tableView: (UITableView *) tableView heightForRowAtIndexPath: (NSIndexPath *) indexPath{
return 38.0f;
}
I add rows via this method
-(void)addBookmark{
NSMutableDictionary* infoDict=[[NSMutableDictionary alloc]init];
NSString* bookmarkTitle=[NSString stringWithFormat:#"This is :[%i]",bookMarksArray.count];
[infoDict setValue:bookmarkTitle forKey:#"bm_title"];
[bookMarksArray addObject:infoDict];
[bookMarkTable reloadData];
}
But when i invoke this method multiply times it seems that all UILabel are added more than once. Here is a result
Any help is appreciated !
What's happening is that each time you move the table, the method is called and adds a new UILabel to the cell.
You should create a subclass of UITableViewCell and add the label there.
Other option, since you are just using one label, is to use the default label of UITableViewCell.
Change
UILabel* bookMarkTitle =[[UILabel alloc]initWithFrame:CGRectMake(50, 0, 370, 40)];
bookMarkTitle.text=[cellDictionary valueForKey:#"bm_title"];
bookMarkTitle.backgroundColor=[UIColor clearColor];
bookMarkTitle.font=[UIFont fontWithName:#"Georgia" size:20.0f];
[cell.contentView addSubview:bookMarkTitle];
to
cell.textLabel.text = [cellDictionary valueForKey:#"bm_title"];
At the begin from - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath you must remove the subviews.
for(UIView* vista in cell.contentView){
[vista removeFromSuperview];
}
And that's all.
PD: Check if the removed view is the correct.
Try to change:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
with:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:nil];
I use bellow codes to show data on TableView but when scrolling, data repeat and other data lost.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [FileCompletedArray count];
}
cellForRowatindexpath ():
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"CellIdentifier";
UITableViewCell *cell = [_tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
UILabel *FileNameLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 0, 100, 30)];
FileNameLabel.backgroundColor = [UIColor clearColor];
FileNameLabel.font = [UIFont fontWithName:#"Helvetica" size:16];
FileNameLabel.font = [UIFont boldSystemFontOfSize:16];
FileNameLabel.textColor = [UIColor blackColor];
NSLog(#"Reseversed TEMP array %#",FileCompletedArray);
FileNameLabel.text =[FileCompletedArray objectAtIndex:indexPath.row];
[cell.contentView addSubview: FileNameLabel];
[FileNameLabel release];
}
return cell;
}
Do you have any solutions? Thanks in advance
use cell Identifier different
For example like bellow...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *CellIdentifier = [NSString stringWithFormat:#"%d,%d",indexPath.section,indexPath.row];
UITableViewCell *cell = [_tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
/// write your code here..
}
}
OR set nil like bellow..
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//static NSString *CellIdentifier = #"CellIdentifier";
UITableViewCell *cell = [_tableView dequeueReusableCellWithIdentifier:nil];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil] autorelease];
/// write your code here..
}
}
This problem is generated because Your UITableView Reuse Cell instant of create new one.
I give you some suggestion that may be helpful for you.
1) add Controller in between
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
/// Your code of initialization of controller;
}
/// set property of controllers such like (Text UILabel, image of UIImageView...etc) .
return cell;
}
1) Add Your Controller to cell.contentView.
EDITED:
Before You follow my Edited Answer i want to tell you that following code is bad for memory management because it will create new cell for each rows of UITableView, so be careful for it.
But it is better for if UITableView Have Limited row about (50-100 may be ) os use following code if is it suitable for you.
NSString *CellIdentifier = [NSString stringWithFormat:#"S%1dR%1d",indexPath.section,indexPath.row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil)
{
/// Your whole code of controllers;
}
You are setting the text of the label only when creating a new cell. However, during cell reuse, new cell is not created. Hence your code for setting/changing text is not working. You can use this modified code.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"CellIdentifier";
UITableViewCell *cell = [_tableView dequeueReusableCellWithIdentifier:CellIdentifier];
UILabel *FileNameLabel=nil;
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
FileNameLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 0, 100, 30)];
FileNameLabel.tag = 1001;
FileNameLabel.backgroundColor = [UIColor clearColor];
FileNameLabel.font = [UIFont fontWithName:#"Helvetica" size:16];
FileNameLabel.font = [UIFont boldSystemFontOfSize:16];
FileNameLabel.textColor = [UIColor blackColor];
[cell.contentView addSubview: FileNameLabel];
[FileNameLabel release];
}
if(!FileNameLabel)
FileNameLabel = [cell.contentView viewWithTag:1001];
FileNameLabel.text =[FileCompletedArray objectAtIndex:indexPath.row];
return cell;
}
Alternatively you can use the default textLabel instead of creating and adding new label
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"CellIdentifier";
UITableViewCell *cell = [_tableView dequeueReusableCellWithIdentifier:CellIdentifier];
UILabel *FileNameLabel=nil;
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
cell.textLabel.font = [UIFont fontWithName:#"Helvetica" size:16];
cell.textLabel.font = [UIFont boldSystemFontOfSize:16];
cell.textLabel.textColor = [UIColor blackColor];
}
cell.textLabel.text =[FileCompletedArray objectAtIndex:indexPath.row];
return cell;
}
I also faced same problem, the problem occurs when we reuse the cells. At the time of reusing the data is already present in it and we write some more data also, to sort out this, i did a minor change to my table view delegate method cellForRowAtIndexPath. Here the code which i use always using table view.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
if (!cell) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"cell"];
}
for (UIView *view in cell.contentView.subviews) {
[view removeFromSuperview];
}
return cell;
}
The for loop gets executed when we are reusing some cell and what it does is removing all the previous data present in UITableViewCell
Hope this will help someone.
I'm having a bit of difficulty understanding what is going wrong and how to fix this.
-(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];
NSUInteger row = [indexPath row];
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.selectionStyle = UITableViewCellSelectionStyleBlue;
UILabel *where = [[UILabel alloc] initWithFrame:CGRectMake(88.0, 0.0, 155.0, 22.0)];
where.text = [delegate.destinationArray1 objectAtIndex:row];
where.font = [UIFont fontWithName:#"Helvetica" size:12.0];
where.textColor = [UIColor blueColor];
[cell.contentView addSubview:where];
return cell;
}
This doesn't work properly but this does:
-(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];
}
NSUInteger row = [indexPath row];
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.selectionStyle = UITableViewCellSelectionStyleBlue;
UILabel *where = [[UILabel alloc] initWithFrame:CGRectMake(88.0, 0.0, 155.0, 22.0)];
where.text = [delegate.destinationArray1 objectAtIndex:row];
where.font = [UIFont fontWithName:#"Helvetica" size:12.0];
where.textColor = [UIColor blueColor];
[cell.contentView addSubview:where];
return cell;
}
They both get populated by "delegate.destinationArray1" but when all the code is inside the curly braces of
if(cell == nil)
the list gets unordered and repeats cells and misses some out. I can't use the latter way as it creates a MASSIVE memory leak when scrolling.
Any ideas?
I did the exact same thing when I started using UITableViews. The reason for the memory leak is that in the second implementation (the one that works) you are actually creating every cell, every single time. Let me try to explain a bit more.
You never want to set content of a cell between the (cell == nil). The reason for this is the reuseIdentifier. If the table needs to display a new cell it will grab one and see if it has already been alloced/inited. If it has it will just use it. If that is the case the content will already be set in the cell you grabbed and you are not telling it to set it any differently.
between the (cell == nil) only create and establish the view. Not the content. All content should be set after. So then no matter what cell it grabs it can always set the content. So this is what you want:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(!cell) // or (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.selectionStyle = UITableViewCellSelectionStyleBlue;
UILabel *where = [[UILabel alloc] initWithFrame:CGRectMake(88.0, 0.0, 155.0, 22.0)];
where.font = [UIFont fontWithName:#"Helvetica" size:12.0];
where.textColor = [UIColor blueColor];
where.tag = 1;
[cell addSubview:where];
}
NSUInteger row = indexPath.row;
UILabel *where = [cell viewWithTag:1];
where.text = [delegate.destinationArray1 objectAtIndex:row];
return cell;
}
I just coded this in StackoverFlow so sorry if there are any small syntax errors.
The cell object is reused or created by the first statement. After checking cell for nil and creating a cell, you must not create another cell.
So delete the line
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
which comes after
NSUInteger row = [indexPath row];
and you'll work with the correct cell object.
When the tableview reuses cells it is based on the CellIdentifier. The tableview doesn't care what attributes you've set on the cell. In the first case the reuse it happening and it recognizes a cell it can use but that cell has the wrong information on it.
What I do is subclass UITableViewCell and do all the work inside of that class. Here is a quick snippet
#implementation AlertCell
//Custom init method
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier withHeight:(float)height {
//Whatever you need to do
}
//Place the views
- (void)layoutSubviews {
}
//Custom Setter method
- (void)setAlert:(CWAlert *)incomingAlert withAssets:(NSDictionary *)assets {
}
#end
Then you do something like this
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier;
CWAlertCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (!cell) {
cell = [[AlertCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier withHeight:[self convertAssetsLengthToCellHeight:assetsLength]];
UIView *selectedView = [[UIView alloc] init];
selectedView.backgroundColor = [UIColor colorWithHexString:#"F6F6F6"];
cell.selectedBackgroundView = selectedView;
}
NSDictionary *alertInfo = [AlertCell getNeededCellAssets:alert];
[cell setAlert:alert withAssets:alertInfo];
return cell;
}
I can show more code from the subclass if needed.
I am using FontLabel in the view cells of the table.
- (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];
}
FontLabel *author_name = [[FontLabel alloc] initWithFrame:CGRectMake(58, 10, 217, 16) fontName:#"MyriadPro-Bold" pointSize:12.0f];
author_name.numberOfLines = 1;
author_name.text = [dummyArray objectAtIndex:indexPath.row];
author_name.textColor = [UIColor colorWithRed:0.580 green:0.776 blue:0.329 alpha:1.000];
author_name.backgroundColor = [UIColor clearColor];
[cell addSubview:author_name];
return cell;
}
But the label is loaded multiple times. I can see that it is getting bolder and bolder. How can I fix it?
When you call addSubview, it's not removing the old view. remember that cells are reused so the view you added in the last iteration is still there.
You should instead subclass UITableViewCell so that you can add a UILabel to it.
Edit:
Or you can do
author_name.tag = 10;
and then
FontLabel *author_name = (FontLabel *)[cell.contentView viewWithTag:10];
when you want to retrieve it.