image in an Expanded TableViewCell is lost after scrolling - iphone

I am creating an application in which i have many table cells(>300). I have successfully implemented expanding and collapsing tableview cells. On expansion an image is displayed which is fetched from a webservice, on clicking the expanded cell, the cell collapses again, if another cell is clicked the previous cell collapsed and current cell expands. Now the problem is if the user scrolls the tableview with the cell expanded table works fine but when he returns
to it the image gets lost, and there is a bit of problem with the functionality as well( the table takes that cell to be collapsed).
Moreover if the user keeps on scrolling the table down he can encounter that image in a collapased cell(which looks very bad), i think its because dequeueReusableCellWithIdentifier is fetching the already expanded cell.
PS: Every image is different based on the cell value but it is fetched in a different call(not al together ie to fetch 300 images i make 300 independent calls).

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UIImageView * imageView;
UILabel * nameLabel;
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier] autorelease];
nameLabel = [[UILabel alloc] initWithFrame:CGRectMake(45.0, 5.0, 245.0, 34.0)];
nameLabel.font = [UIFont fontWithName:CELL_FONT size:CELL_FONT_SIZE];
nameLabel.tag = 2;
nameLabel.backgroundColor = [UIColor clearColor];
[cell.contentView addSubview:nameLabel];
[nameLabel release];
imageView = [[UIImageView alloc] initWithFrame:CGRectMake(5.0, 5.0, 30.0, 30.0)];
imageView.tag = 1;
imageView.contentMode = UIViewContentModeScaleAspectFit;
[cell.contentView addSubview:imageView];
[imageView release];
}
else {
imageView = (id)[cell.contentView viewWithTag:1];
nameLabel = (id)[cell.contentView viewWithTag:2];
}
return cell;
}

Related

UILabels within a UITableView cell are overlaying each other in iOS7

I didn't have this problem with iOS6, but am currently having it with iOS7. I have a UITableView and you can see 8 cells at the time the view is loaded. Each populated with different names from and array. If you scroll down, the next two cells look good, but everything past that gets text laid on top of it; That text being the contents of what was in the previous cells. So the 10th cell will have what was in the first cell, as well as what is supposed to be in the 10th cell laid on top of it.
Code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
//Create Label for Name inside cell
UILabel *name = [[UILabel alloc] initWithFrame:CGRectMake( 7.0, 5.0, 300.0, 30.0 )];
[name setText:[self.entriesArray objectAtIndex:indexPath.row]];
//Check to see if current person is a Parent or Child
NSString *class = [self.database getCellDataWithMembership:[self.MembershipArray objectAtIndex:indexPath.row] andColIndex:4];
if([class isEqualToString:#"CHILD"])
{
name.textColor = [UIColor colorWithRed:25.0f/255.0f green:111.0f/255.0f blue:45.0f/255.0f alpha:1.0f];
name.font = [UIFont fontWithName:#"Helvetica-Bold" size:17.0];
}
[cell.contentView addSubview:name];
return cell;
}
My skill with Table views is makeshift at best. I've been reading lots of documentation and researching solutions, but was not able to come up with a solution. I just find it odd that it works perfect for iOS6, but not for iOS7.
So it fetches a person's name from an array and I want to populate the cells with those names. I was able to originally accomplish this using:
cell.textLabel.text = [self.entriesArray objectAtIndex:indexPath.row];
if([class isEqualToString:#"CHILD"])
{
cell.textLabel.textColor = [UIColor colorWithRed:25.0f/255.0f green:111.0f/255.0f blue:45.0f/255.0f alpha:1.0f];
cell.textLabel.font = [UIFont fontWithName:#"Helvetica-Bold" size:17.0];
If I use that instead of the "name" UILabel actions from the first code block, then it displays the names perfectly with no text overlay, but what becomes an issue is the text color. If they are labeled as a CHILD then they should be green text and bold. However, after scrolling down, every person becomes green when they shouldn't be.
Sorry for the lengthy question. I've been working on this and racking my brain around it and I just can't seem to figure it out. Any help would be greatly appreciated.
I'm dynamically adding UI objects to cells. As "caglar" notes, adding and then removing is probs not the best-practice. But, I am doing this also. The way I get around adding loads of UI objects to the cell, each time it's displayed, is by removing all my subviews first. The willDisplayCell delegate then adds them back. Clearly, if you want to remove only certain views, you'll have to tag the view and be more selective with your removal. But you can remove all with the following.
-(void)tableView:(UITableView *)tableView
willDisplayCell:(UITableViewCell *)cell
forRowAtIndexPath:(NSIndexPath *)indexPath {
[[cell.contentView subviews] makeObjectsPerformSelector:#selector(removeFromSuperview)];
}
Just ensure you're adding / removing your labels to the cell's contentView. In iOS7, you'll remove that too, if you're not careful.
Hope it helps you out.
In your code, labels are added to cell whenever cellForRowAtIndexPath: method is called. I mean you add labels many times. You can remove the label which was added before.
//If label was added with tag = 500, remove it
for (UIView *sv in cell.contentView.subviews)
{
if (sv.tag == 500)
{
[sv removeFromSuperview];
}
}
//Create Label for Name inside cell
UILabel *name = [[UILabel alloc] initWithFrame:CGRectMake( 7.0, 5.0, 300.0, 30.0 )];
[name setText:[self.entriesArray objectAtIndex:indexPath.row]];
name.tag = 500;
However, this solution is not a good solution. I think creating a custom UITableViewCell is the right thing to do.
You can try this method, when the cell is nil, you need to creare the UILabel* name, then you set the name label with a tag name.tag = 1000, then you can access this label with this method UILabel* name = (UILabel*)[cell.contentView viewWithTag:1000];.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
//Create Label for Name inside cell
UILabel *name = [[UILabel alloc] initWithFrame:CGRectMake( 7.0, 5.0, 300.0, 30.0 )];
name.tag = 1000;
[cell.contentView addSubview:name];
}
UILabel* name = (UILabel*)[cell.contentView viewWithTag:1000];
[name setText:[self.entriesArray objectAtIndex:indexPath.row]];
//Check to see if current person is a Parent or Child
NSString *class = [self.database getCellDataWithMembership:[self.MembershipArray objectAtIndex:indexPath.row] andColIndex:4];
if([class isEqualToString:#"CHILD"])
{
name.textColor = [UIColor colorWithRed:25.0f/255.0f green:111.0f/255.0f blue:45.0f/255.0f alpha:1.0f];
name.font = [UIFont fontWithName:#"Helvetica-Bold" size:17.0];
}
return cell;
}
You can set uilabels by using ios6/7 delta shown is size inspector .firstly set your total view for ios7 by changing values x,y,width,height and then change value in ios6/7 delta to make it for ios6 .Hope you get
you may change the this code.
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath]; -> UITableViewCell *cell = nil;

UITableViewCell image changes when scrolling

I have a UITableView with a title and an image on each cell. Some cells will have a default image and others will not. When I scroll the table, the image of some rows is not the expected and the image of another row gets displayed instead of the expected one. If I don't use dequeuereuseidentifier everything works fine, but I want to use it because I have lots of cells.
Any suggestion?
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"MyCell"];
if (cell == nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"MyCell"];
CGRect titleRect = CGRectMake(60, 6, 200, 24);
UILabel *title = [[UILabel alloc] initWithFrame: titleRect];
title.tag = 1;
title.backgroundColor = [UIColor clearColor];
title.font = [UIFont fontWithName:#"AdelleBasic-Bold" size:15.5];
[cell.contentView addSubview:title];
UIImageView *defaultCellImage = [[UIImageView alloc] initWithFrame:CGRectMake(8, 10, 42, 42)];
defaultCellImage.tag = 2;
[defaultCellImage setImage:[UIImage imageNamed: #"Default_Row_Image"]];
[cell.contentView addSubview:defaultCellImage];
}
NSUInteger row = [indexPath row];
Movie *movie = [_movies objectAtIndex: row];
UILabel *titleRowLabel = (UILabel *) [cell.contentView viewWithTag:1];
titleRowLabel.text = [movie title];
UIImageView *cellImage = (UIImageView *) [cell.contentView viewWithTag:2];
if (![movie.imageName isEqualToString:#""])
[cellImage setImage:[UIImage imageNamed: [movie imageName]]];
return cell;
}
The first cells to be used in your table view will be properly loaded. Since there is no cell to dequeue, the if (cell == nil) will return YES and your cell will have its image set to be the default. Then, if your condition for setting a different image is satisfied later in the method, a different image will be shown. So far, so good.
However, when a reusable cell is dequeued, it already has an image set, which might not be the default. Since cell == nil will now return NO, this cell will never have its image reset to the default one, even if it is the image that should be shown.

How to clear UILabels inside UITableViewCells?

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;
}

Buggish behavior of a UILabel Text when selecting a Custom built UITableViewCell: the text get mixup or overlaid with a previously loaded label

I have been looking for a solution to this issue for a few days now... and cannot find someone with a similar problem or a solution that would work for me. At this point I am not even sure that I am doing something wrong, as I have read and analyzed many sample code and I am almost 100% sure that I am doing this the way it should...
Anyway here it comes:
I have a UITableView to which I display custom built UITableViewCell, here is where I create them:
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"CellIdentifier";
NSDictionary *myDictionary = [myArray objectAtIndex:indexPath.row];
UITableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero
reuseIdentifier: CellIdentifier] autorelease];
CGRect textViewRect = CGRectMake(10.0, 0.0, 250, 25);
UILabel *textView = [[UILabel alloc] initWithFrame:textViewRect];
textView.text = [myDictionary objectForKey:#"name"];
textView.font = [UIFont systemFontOfSize:12.0];
textView.textColor = [UIColor blackColor];
textView.highlightedTextColor = [UIColor whiteColor];
textView.textAlignment = UITextAlignmentRight;
[cell.contentView addSubview:textView];
[textView release];
CGRect imageRect = CGRectMake(270.0, 15, 16, 16);
UIImageView *icon = [[UIImageView alloc] initWithFrame:imageRect];
icon.image = [myDictionary objectForKey:#"color-icon"];
icon.highlightedImage = [myDictionary objectForKey:#"gray-icon"];
[cell.contentView addSubview:icon];
[icon release];
}
So as you can see, pretty standard stuff... Then when I click on one of the cell, another view gets loaded instead of the table.
Until now, everything is fine, but then when I come back to that table view and that it has to reload the problem starts...
By the way I have added this to the delegate methods so the cells never stay selected:
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
// [...] a lot more code here
}
When I clicked on my cell in the simulator with the mouse and keep it down the cell stays selected as expected (same way on the device itself) and this is why I get:
[Image 1]
The UILabel Text is totally mixed up ! The screenshot is actually of the last cell of the table and the overlapping text is the one of the first cell. And the behavior on the first is similar, if I maintain the click on it, it will show the same behavior mixing up with the UILabel text of the last cell. I am guessing that is is due to the way the dequeueReusableCellWithIdentifier works (probably a FILA queue).
Of course I tried to work around that and found some really weird stuff.
If I don't click the cells are perfect, no bugs, the correct text is displayed etc:
[Image 2]
Then I tried to mess up a little bit with the parameters of my UILabel. I added this:
textView.backgroundColor = [UIColor clearColor];
And when I do this, as soon as the table reload, then I don't even need to highlight the cell to see the screw up behavior:
[Image 3]
The only way I was about to get rid of the problem to always instantiate a new cell rather than dequeueing one...
UITableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero
reuseIdentifier: CellIdentifier] autorelease];
was replaced by:
UITableViewCell *cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero
reuseIdentifier: CellIdentifier] autorelease];
But of course this won't work on the long term because of the memory leak...
Also, it is to be noted that I have the exact same behavior for another UITableView in another view somewhere in this App... The other custom cell is more complex, more labels, more images, etc, but all the label exhibit the same behavior. And this more complex Table View is managed by a Navigation Controller, so no custom loading / unloading like the first one...
That's all I have, and I can't find a solution... please help !
Arghh this is really annoying... I am new so I cannot post images... :(
Here is a link where you can see the referenced images: https://skitch.com/aponsin/rne9k/fullscreen.png-100-layer-3-rgb-8
Alex
The problem is that you create new label and add it to cell each time cell is being reused. To fix that you must create your label only when your cell is created:
if (cell == nil){
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero
reuseIdentifier: CellIdentifier] autorelease];
CGRect textViewRect = CGRectMake(10.0, 0.0, 250, 25);
UILabel *textView = [[UILabel alloc] initWithFrame:textViewRect];
textView.tag = kLabelTag;
textView.font = [UIFont systemFontOfSize:12.0];
textView.textColor = [UIColor blackColor];
textView.highlightedTextColor = [UIColor whiteColor];
textView.textAlignment = UITextAlignmentRight;
[cell.contentView addSubview:textView];
[textView release];
CGRect imageRect = CGRectMake(270.0, 15, 16, 16);
UIImageView *icon = [[UIImageView alloc] initWithFrame:imageRect];
icon.image = [myDictionary objectForKey:#"color-icon"];
icon.highlightedImage = [myDictionary objectForKey:#"gray-icon"];
[cell.contentView addSubview:icon];
[icon release];
}
And after that you can get your label from cell using tag property you've assigned:
UILabel *textView = (UILabel*)[cell.contentView viewWithTag:kLabelTag];
textView.text = [myDictionary objectForKey:#"name"];
same logic also applies to setting up your icon imageview if it varies in different cells
Also have a look at components standard UITableViewCell already provides (depending on its cell style) - there's already UIImageView and UILabels there and you can set your custom properties to them and use them without creating extra components

Centering Subviews in UITableViewCell within grouped TableView

I'm trying to figure out how to place a subview to a custom UITableViewCell with centered position. As stated in the documentation (Customizing Cells) one should "...add subviews to the contentView property of the cell object or ...". As I noticed it works fine with UITableViewStylePlain. In UITableViewStyleGrouped tables, subviews can not be placed centered. They are shifted to the right hand side.
If the subview is added to UITableViewCell directly, it's fine with both modes. The same is true, if I subclass the UITableViewCell and load the cell from XIB.
Unfortunately, I can't upload screenshots. Can anyone help fix the issue? Or do I miss something vital, as the misalignment seems to match the dimension to be shrunken in grouped table.
Many thanks,
El
- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier1 = #"AddToCell";
static NSString *cellIdentifier2 = #"AddToContentView";
static NSString *aVeryLongLine = #"---------------------------------------------";
UITableViewCell *cell = nil;
if (indexPath.section == 0) {
cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier1];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:cellIdentifier1] autorelease];
CGRect frame = cell.frame;
CGRect labelFrame = CGRectMake((frame.size.width-270)/2, (frame.size.height-40)/2, 270, 40);
UILabel *label = [[UILabel alloc] initWithFrame:labelFrame];
label.textAlignment = UITextAlignmentCenter;
label.text = aVeryLongLine;
[cell addSubview:label];
[label release];
}
}
else if (indexPath.section == 1) {
cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier2];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:cellIdentifier2] autorelease];
CGRect frame = cell.contentView.frame;
CGRect labelFrame = CGRectMake((frame.size.width-270)/2, (frame.size.height-40)/2, 270, 40);
UILabel *label = [[UILabel alloc] initWithFrame:labelFrame];
label.textAlignment = UITextAlignmentCenter;
label.text = aVeryLongLine;
[cell.contentView addSubview:label];
[label release];
}
}
else {
}
return cell;
}
Instances of UITableViewCell resize their content views under a number of circumstances (for example, when temporarily adding a delete button to allow the user to remove a row).
When cells are displayed in a grouped style table view, they're resized to provide a margin between the cells and the left and right edges of the table view. So for your subviews to stay positioned correctly, you'll need to set their autoresizing masks appropriately, something like this:
mySubview.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin;
(or
[mySubview setAutoresizingMask:(UIViewAutoresizingFlexibleWidth |
UIViewAutoresizingFlexibleLeftMargin |
UIViewAutoresizingFlexibleRightMargin)];
for folks who prefer the old syntax.)
Did you check the frame's value, which come from cell.contentView.frame or cell.frame ?
When the cell is initialized with style and identity, it maybe have a CGZeroRect for his frame value.