I am loading a UITableView in this way:
- (UITableViewCell *)tableView:(UITableView *)tableViewLocal cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
CustomTableViewCell *cell = [tableViewLocal dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[CustomTableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
for(UIView *subview in cell.contentView.subviews)
{
[subview removeFromSuperview];
}
UIImage* img;
UIImageView *imv = [[UIImageView alloc]initWithFrame:CGRectMake(5, 5, 60, 60)];
if(isFiltered == TRUE){
cell.textLabel.text = [filteredTableData objectAtIndex:indexPath.row];
cell.textLabel.font = [UIFont systemFontOfSize:14];
}
if(isFiltered == FALSE){
cell.textLabel.text = [itemArray objectAtIndex:indexPath.row];
cell.textLabel.font = [UIFont systemFontOfSize:14];
cell.detailTextLabel.text = [NSString stringWithFormat:#"date added: %#", [DKStoreManager dateFileWasCreatedWithFileName:[itemArray objectAtIndex:indexPath.row] inFolderNumber:[_FolderCode intValue] forUser:[_PassedUserID intValue] andType:_FolderType]];
}
NSData* data = [DKStoreManager loadFileWithName:[itemArray objectAtIndex:indexPath.row] forFolderNumber:[_FolderCode intValue] forUser:userID andType:_FolderType];
img = [[UIImage imageWithData:data] cropToSize:CGSizeMake(320, 320) usingMode:NYXCropModeCenter];
imv.image = img;
[cell.contentView addSubview:imv];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
As you can see I have an itemArray with all the names of the files, and for each cell I load the relative NSData in this way:
NSData* data = [DKStoreManager loadFileWithName:[itemArray objectAtIndex:indexPath.row] forFolderNumber:[_FolderCode intValue] forUser:userID andType:_FolderType];
Since it also loads images (and there may be more than 300 cells), the UI frees.
I have tried loading only the visible cells using the accepted answer of this link:
tableView: cellForRowAtIndexPath: get called not only for visible cells?
however all of the cells are loaded at the same time. I have no idea of how to do this...
cellForRowAtIndexPath gets called when the tableView reloads as well as when the user scrolls. The UI freeze could be due to the fact that your calling
for(UIView *subview in cell.contentView.subviews)
{
[subview removeFromSuperview];
}
UIImageView *imv = [[UIImageView alloc]initWithFrame:CGRectMake(5, 5, 60, 60)];
which means that every time the user scrolls , you are iterating through all the subViews and removing them, as well as allocating UIimageView's at the same time, this is not a good way to go about displaying content. You can use the tableViewCell's default imageView property to display your image. After getting you image just say
cell.imageView.image = img;
Related
I'm using an if statement so that only specific cells gets images. In my test examples there is only one cell that should get an image and the if statement gets run only once. The if statement also changes the text of the labels. The labels are correctly changed but the image is added to multiple cells especially when I scroll up and down. How to I get it to not add extra images to other cells.
UIImageView *imageView= [[UIImageView alloc]initWithFrame:CGRectMake(114,5, 122, 63)];
if (condition) {
[imageView setImageWithURL:url placeholderImage:[UIImage imageNamed:#"Placeholder.png"]];
imageView.tag = 777;
[cell addSubview:imageView];
cell.titleLabel.text = [dict valueForKey:#"name"];
cell.titleDescription.text = [dict valueForKey:#"summary"];
} else {
[[cell viewWithTag:777] removeFromSuperview];
}
The UITableViewCell is cached, so instead of always creating a new UIImageView, check first if it has one:
UIImageView * imageView = (UIImageView*)[cell viewWithTag:777];
if (condition) {
if(!imageView) {
imageView= [[UIImageView alloc]initWithFrame:CGRectMake(114,5, 122, 63)];
}
[imageView setImageWithURL:url placeholderImage:[UIImage imageNamed:#"Placeholder.png"]];
imageView.tag = 777;
[cell addSubview:imageView];
cell.titleLabel.text = [dict valueForKey:#"name"];
cell.titleDescription.text = [dict valueForKey:#"summary"];
} else {
[imageView removeFromSuperview];
}
You were likely adding multiple imageViews to one cell, so removeFromSuperView was only removing the first one.
Do like this
during the creation of cell that is
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath
{
UITableViewCell *cell = [aTableVIew dequeueReusableCellWithIdentifier:#"cell"];
if(cell == nil)
{
cell = [[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"]autorelease];
UIImageView *aImgView = [[UIImageView alloc]initWithFrame:CGRectMake(20, 0, 40, 40)];
aImgView.tag = 777;
[cell addSubview:aImgView];
[aImgView release];
}
//use your condition hear onwards to make changes
if(indexPath.section == 0)
{
UIImageView *view = (UIImageView *)[cell viewWithTag:777];
view.image = [UIImage imageNamed:#"peter.png"];
}
else if (indexPath.section == 1)
{
if(indexPath.row == 0 )
{
UIImageView *view = (UIImageView *)[cell viewWithTag:777];
view.image = nil;
}
else
{
UIImageView *view = (UIImageView *)[cell viewWithTag:777];
view.image = [UIImage imageNamed:#"peter.png"];
}
}
return cell;
}
change according to requirement
note: i am not using ARC
So I am having trouble showing my data in a UITableView. I do believe it has something to do with reusing the cells. I have checked online and here at SO but have not found a solution that works for me. Any help would be appreciated.
I have an Array that is populated by text and pictures. I am then showing the information in a tableView. If I were to use static sized cells everything works out fine, but the amount of text changes, so I have also implemented the heightForRowAtIndexPath method. This works as well, until I scroll all the way down to the bottom.
After that, when I scroll back up, all the cell heights change and the display gets all jumbled. Some text gets cut off, pictures get chopped and some of the cells only have the last portion of text. I really think it has something to do with reusing the cells, but I don’t know how to attack this problem. Below is my code for cellForRowAtIndexPath and heightForRowAtIndexPath.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
if ([[_theBigArray objectAtIndex:indexPath.row] isKindOfClass:[NSString class]])
{
NSString *label = [_theBigArray objectAtIndex:indexPath.row];
CGSize stringSize = [label sizeWithFont:[UIFont systemFontOfSize:15] constrainedToSize:CGSizeMake(320, 9999) lineBreakMode:NSLineBreakByWordWrapping];
UITextView *textV = [[UITextView alloc] initWithFrame:CGRectMake(5, 5, 290, stringSize.height +50)];
textV.font = [UIFont systemFontOfSize:15];
textV.text = [_theBigArray objectAtIndex:indexPath.row];
textV.textColor = [UIColor blackColor];
textV.editable = NO;
[cell.contentView addSubview:textV];
}
else if ([[_theBigArray objectAtIndex:indexPath.row] isKindOfClass:[UIImage class]])
{
UIImageView *imageV = [[UIImageView alloc] initWithFrame:CGRectMake(5, 5, 290, 100)];
imageV.contentMode = UIViewContentModeScaleAspectFit;
imageV.image = [_theBigArray objectAtIndex:indexPath.row];
[cell.contentView addSubview:imageV];
}
return cell;
[tableView reloadData];
}
For heightForRowAtIndexPath
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
int rowHeight = 0.0f;
if ([[_theBigArray objectAtIndex:indexPath.row] isKindOfClass:[NSString class]])
{
NSString *temp = [_theBigArray objectAtIndex:indexPath.row];
CGSize size = [temp sizeWithFont:[UIFont systemFontOfSize:14.0f] constrainedToSize:CGSizeMake(320, 9999) lineBreakMode:NSLineBreakByWordWrapping];
rowHeight = size.height+50;
}
else if ([[_theBigArray objectAtIndex:indexPath.row] isKindOfClass:[UIImage class]])
{
rowHeight = 115.0f;
}
//NSLog(#"rowHeight is %i", rowHeight);
return rowHeight;
[tableView reloadData];
}
I even tried to make two different cells and call them separately, but the same thing happens. I did still use the same heightForRowAtIndexPath method.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *newCell = [[UITableViewCell alloc] init];
if ([[_theBigArray objectAtIndex:indexPath.row] isKindOfClass:[NSString class]])
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell"];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Cell"];
}
NSString *label = [_theBigArray objectAtIndex:indexPath.row];
CGSize stringSize = [label sizeWithFont:[UIFont systemFontOfSize:15] constrainedToSize:CGSizeMake(320, 9999) lineBreakMode:NSLineBreakByWordWrapping];
UITextView *textV = [[UITextView alloc] initWithFrame:CGRectMake(5, 5, 290, stringSize.height +50)];
textV.font = [UIFont systemFontOfSize:15];
textV.text = [_theBigArray objectAtIndex:indexPath.row];
textV.textColor = [UIColor blackColor];
textV.editable = NO;
[cell.contentView addSubview:textV];
newCell = cell;
}
else if ([[_theBigArray objectAtIndex:indexPath.row] isKindOfClass:[UIImage class]])
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"PictureCell"];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"PictureCell"];
}
UIImageView *imageV = [[UIImageView alloc] initWithFrame:CGRectMake(5, 5, 290, 100)];
imageV.contentMode = UIViewContentModeScaleAspectFit;
imageV.image = [_theBigArray objectAtIndex:indexPath.row];
[cell.contentView addSubview:imageV];
newCell = cell;
}
return newCell;
[tableView reloadData];
}
Any ideas?
The main problem is that you're adding subviews to cells every time they scroll in, but when a cell is reused, it will already have those subviews added. (That is, when a cell is reused, it will already have a UITextView or UIImageView depending on the reuse identifier.)
You need to check if these subviews exist first; this is commonly done by using the -[UIView viewWithTag] method, or by subclassing UITableViewCell and assigning each view as a property.
(You can take a look at the SO question How to get other control value from UITableViewCell? to see how to use viewWithTag. I would avoid subclassing UITableViewCell until you're more comfortable with the out-of-the-box implementation.)
Also, this line of code:
UITableViewCell *newCell = [[UITableViewCell alloc] init];
is a terrible idea, because you are creating a new UITableViewCell without checking to see if you can reuse one first. This defeats the entire purpose of reusing cells, which is fast scrolling performance. Instead, just declare it without initializing it:
UITableViewCell *newCell;
Also, in heightForRowAtIndexPath, you are
declaring rowHeight as an int (it should be a CGFloat)
trying to call reloadData after the method returns (which will never happen, but you should never try to call reloadData from this method)
I need to display the cell data. Actually if I debug the code I can see that the cell.label.text does have correct value, but nothing is getting displayed on the simulator. I have set the row count in numberOfRowsInSection method.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *identifier = #"Cell";
LogTableCell *cell = (LogTableCell *)[tableView dequeueReusableCellWithIdentifier:identifier];
CGRect frame1 = [ self.view frame];
frame1.origin.x=22.0f;
frame1.origin.y=55.0f;
frame1.size.width = 298.0f;
frame1.size.height= 425.0f;
[self.view.superview setFrame:frame1];
int btnWidth = ((self.view.frame.size.width-16)/3);
if(cell == nil)
{
cell = [[LogTableCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
}
LogItem *lg = [[LogItem alloc]init];
lg = [arrLogs objectAtIndex:indexPath.row ];
NSLog(#"%d",indexPath.row);
cell.lblname.textColor=[UIColor whiteColor];
cell.lblsubtype.textColor=[UIColor whiteColor];
cell.lbltime.textColor=[UIColor whiteColor];
cell.lblname.font=[UIFont fontWithName:#"Merriweather" size:15.0];
cell.lblsubtype.font=[UIFont fontWithName:#"Merriweather-Light" size:13.0];
cell.lbltime.font=[UIFont fontWithName:#"Merriweather-Light" size:13.0];
UIImageView *imageview = [[UIImageView alloc] initWithFrame:CGRectMake(1, cell.contentView.frame.size.height, 298.0,2)] ;
imageview.image = [UIImage imageNamed: #"lineseperator.png"];
[cell.contentView addSubview:imageview];
cell.lblname.text = lg.name;
NSLog(#"%#",lg.name);
[[cell imgtype] setImage:[UIImage imageNamed:lg.imagetype]];
if([lg.subtype length] == 0){
NSLog(#"%#",lg.subtype);
cell.lblsubtype.text = lg.time;
cell.lbltime.text = #"";
}
else{
NSLog(#"%#",lg.subtype);
cell.lblsubtype.text = lg.subtype;
cell.lbltime.text = lg.time;
}
return cell;
}
The imageview you're adding to the cell is covering all other content. You'll need to either resize/reposition it, or just use the already existing cell.imageView instead.
What is wrong with this code? The image is not displayed. Appreciate any help...
Stepping through the code, I can see that all the variables are updated correctly. The code executes without any errors. The image is not seen though.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *ModuleViewCellId = #"ModuleViewCellId";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ModuleViewCellId];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ModuleViewCellId] autorelease];
}
NSUInteger row = [indexPath row];
NSDictionary *step = [self.module.steps objectAtIndex:row];
cell.textLabel.text = [step objectForKey:kStepTitleKey];//;
cell.textLabel.font = [UIFont fontWithName:#"Helvetica-Bold" size:14.0];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.backgroundColor = [UIColor clearColor];
cell.indentationWidth = 50;
cell.indentationLevel = 1;
//2/6 shp - add icons to the table view
NSString *imagename = [step objectForKey:kStepIconKey];
NSLog(#"%#",imagename);
UIImageView *image;
image = [[[UIImageView alloc]initWithFrame:CGRectMake(0, 0, 57, 57)] autorelease];
image.tag = 1000 + row;
image.contentMode = UIViewContentModeScaleAspectFit;
image.hidden = FALSE;
[image setImage: [UIImage imageNamed:imagename]];
[cell.contentView addSubview:image];
return cell;
}
I just found the answer. The problem was with the path to the file names. All my image files are stored in a bundle. So even though the image file names are correctly referenced, the path needed to be appended.
Adding the path this way fixed the problem.
NSString *imagename = [NSString stringWithFormat: #"%#%#", #"Assets.bundle/assets_dir/",[step objectForKey:kStepIconKey]];
This answer also helped me. UITableViewCell with images in different dimensions
Since you are using default cell i.e uitableViewCell, make use of imageview property of the cell.
UITableViewCell *cell =[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
cell.imageView.image = [UIImage imageNamed:#"ImageName"];
cell.imageView.contentMode = UIViewContentModeScaleAspectFit;
I used the following code to implement cell for every row at index path:
But the problem is when I scroll the tableView, the cell will load a lot of UIImageView *itemimageview in one cell in one line, I tried use
for (UIImageView *sView in cell.subviews) {
[sView removeFromSuperview];
}
but it would remove all subviews of one cell. How to solve this problem?...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSUInteger row = [indexPath row];
NSUInteger oldRow = [lastIndexPath row];
static NSString *CheckMarkCellIdentifier = #"CheckMarkCellIdentifier";
//dequeueReusableCellWithIdentifier --
// Returns a reusable table-view cell object located by its identifier.
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CheckMarkCellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CheckMarkCellIdentifier] autorelease];
}
/*
for (UIImageView *sView in cell.subviews) {
[sView removeFromSuperview];
}
*/
UIImageView *itemimageview=[[UIImageView alloc]initWithFrame:CGRectMake(5, 5, 232, 54)];
itemimageview.image=[UIImage imageNamed:[tabsImageArray objectAtIndex:row]];
itemimageview.userInteractionEnabled = YES;
[cell.contentView addSubview:itemimageview];
[itemimageview release];
UIImageView *dictIcon=[[UIImageView alloc]initWithFrame:CGRectMake(30, 18, 30, 30)];
dictIcon.image=[UIImage imageNamed:#"dictionary_icon.png"];
dictIcon.userInteractionEnabled = YES;
[cell.contentView addSubview:dictIcon];
[dictIcon release];
UILabel *dictNameLabel = [[UILabel alloc] initWithFrame:CGRectMake(80, 23, 100, 21)];
dictNameLabel.text = dictName;
dictNameLabel.textColor = [UIColor whiteColor];
dictNameLabel.shadowColor = [UIColor blackColor];
dictNameLabel.backgroundColor = [UIColor clearColor];
dictNameLabel.userInteractionEnabled = YES;
[cell.contentView addSubview:dictNameLabel];
[dictNameLabel release];
//cell.textLabel.text = [tabsImageArray objectAtIndex:row];
cell.accessoryType = (row == oldRow && lastIndexPath != nil) ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone;
return cell;
}
Consider running through and checking [view isKindOfClass:[UIImageView class]] to check whether the view is the right type of view to remove.
Also consider tagging the views with the UIView tag property, so you can add the subviews once, and then won't have to recreate them with reuse.
Here is how you would do this:
#define ImageViewOneTag 1001
#define ImageViewTwoTag 1002
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)path {
static NSString *CellID = #"CellID";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellID];
UIImageView *imageViewOne = nil;
UIImageView *imageViewTwo = nil;
if (cell) {
// You've caught a reusable cell. Fetch the image views by their tag.
imageViewOne = (UIImageView *)[cell viewWithTag:ImageViewOneTag];
imageViewTwo = (UIImageView *)[cell viewWithTag:ImageViewTwoTag];
} else {
// You haven't got a reusable cell. Make one, and make and add the image views to the contentView.
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellID];
imageViewOne = [[UIImageView alloc] initWithFrame:CGRectMake(0.0, 0.0, 20.0, 20.0)];
[imageViewOne setTag:ImageViewOneTag];
imageViewTwo = [[UIImageView alloc] initWithFrame:CGRectMake(0.0, 20.0, 20.0, 20.0)];
[imageViewTwo setTag:ImageViewTwoTag];
UIView *contentView = cell.contentView;
[contentView addSubview:imageViewOne];
[contentView addSubview:imageViewTwo];
}
// By this stage, you've either retrieved a reusable cell, or you've made a new one. Either way, imageViewOne and imageViewTwo now have a reference to the views you mean.
imageViewOne.image = *imageOneForRow*;
imageViewTwo.image = *imageTwoForRow*;
return cell;
}
I suggest you using custom table view cell, just create a cocoa touch class which inherits uitableviewcell.