How to load images into Custom UITableViewCell? - iphone

Here's what I need to do:
Load 66px x 66px images into the table cells in the MainViewController table.
each TableCell has a unique image.
But how? Would we use cell.image?
cell.image = [UIImage imageNamed:#"image.png"];
If so, where? Is an if/else statement required?
To load each cell's labels, MainViewController uses an NSDictionary and NSLocalizedString like so:
//cell one
menuList addObject:[NSDictionary dictionaryWithObjectsAndKeys:
NSLocalizedString(#"PageOneTitle", #""), kTitleKey,
NSLocalizedString(#"PageOneExplain", #""), kExplainKey, nil]];
//cell two
menuList addObject:[NSDictionary dictionaryWithObjectsAndKeys:
NSLocalizedString(#"PageOneTitle", #""), kTitleKey,
NSLocalizedString(#"PageOneExplain", #""), kExplainKey, nil]];
...
// this is where MainViewController loads the cell content
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
MyCustomCell *cell = (MyCustomCell*)[tableView dequeueReusableCellWithIdentifier:kCellIdentifier];
if (cell == nil)
{
cell = [[[MyCustomCell alloc] initWithFrame:CGRectZero reuseIdentifier:kCellIdentifier] autorelease];
}
...
// MyCustomCell.m adds the subviews
- (id)initWithFrame:(CGRect)aRect reuseIdentifier:(NSString *)identifier
{
self = [super initWithFrame:aRect reuseIdentifier:identifier];
if (self)
{
// you can do this here specifically or at the table level for all cells
self.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
// Create label views to contain the various pieces of text that make up the cell.
// Add these as subviews.
nameLabel = [[UILabel alloc] initWithFrame:CGRectZero]; // layoutSubViews will decide the final frame
nameLabel.backgroundColor = [UIColor clearColor];
nameLabel.opaque = NO;
nameLabel.textColor = [UIColor blackColor];
nameLabel.highlightedTextColor = [UIColor whiteColor];
nameLabel.font = [UIFont boldSystemFontOfSize:18];
[self.contentView addSubview:nameLabel];
explainLabel = [[UILabel alloc] initWithFrame:CGRectZero]; // layoutSubViews will decide the final frame
explainLabel.backgroundColor = [UIColor clearColor];
explainLabel.opaque = NO;
explainLabel.textColor = [UIColor grayColor];
explainLabel.highlightedTextColor = [UIColor whiteColor];
explainLabel.font = [UIFont systemFontOfSize:14];
[self.contentView addSubview:explainLabel];
//added to mark where the thumbnail image should go
imageView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 66, 66)];
[self.contentView addSubview:imageView];
}
return self;
}

If the image is going to be the same for every cell, i.e., it's part of that type of cell, you could load it in MyCustomCell's init, using self.image = [UIImage imageNamed:"blabla"];
Otherwise, if the image will be different for different cells, it would be more logical to put it in tableView:cellForRowAtIndexPath:

Yes, cell.image is deprecated. use imageview.image instead in the default TableViewCell. I am not sure why custom cell was required to do what the standard tableviewcell already does (title, subtitle, and an image using UITableViewStyleSubtitle)

It works now. You were right, Seventoes, about putting it in tableView:cellForRowAtIndexPath:
indexPath.row was what I was I missing. The working result goes like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
MyCustomCell *cell = (MyCustomCell*)[tableView dequeueReusableCellWithIdentifier:kCellIdentifier];
if (cell == nil)
{
cell = [[[MyCustomCell alloc] initWithFrame:CGRectZero reuseIdentifier:kCellIdentifier] autorelease];
}
if (indexPath.row == 1)
{
cell.image = [UIImage imageNamed:#"foo.png"];
}
else if (indexPath.row == 2)
cell.image = [UIImage imageNamed:#"bar.png"];
}
...
else
{
cell.image = [UIImage imageNamed:#"lorem.png"];
}
return.cell;
}

A better approach then that if-else mess would be to push your images onto a NSMutableArray in the right order, and then just use
cell.image = [myImages objectAtIndex:indexPath.row];

Related

UITableView performance issues when adding UIViews to cell.contentView

I am experiencing performance problems when using some subviews on my UITableViewCells. After I keep scrolling it eventually starts getting very slow.
First step I am doing is creating a common UIView for every cell, essentially this is creating a white cell with a rounded effect on the cell with a shadow. The performance for this seems to be normal so I don't think it's the culprit.
Here is the code I am using to do this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *NewsCellIdentifer = #"NewsCellIdentifier";
NewsItem *item = [self.newsArray objectAtIndex:indexPath.row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:NewsCellIdentifer];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:NewsCellIdentifer];
cell.contentView.backgroundColor = [UIColor clearColor];
UIView *whiteRoundedCornerView = [[UIView alloc] initWithFrame:CGRectMake(10,10,300,100)];
whiteRoundedCornerView.backgroundColor = [UIColor whiteColor];
whiteRoundedCornerView.layer.masksToBounds = NO;
whiteRoundedCornerView.layer.cornerRadius = 3.0;
whiteRoundedCornerView.layer.shadowOffset = CGSizeMake(-1, 1);
whiteRoundedCornerView.layer.shadowOpacity = 0.5;
[cell.contentView addSubview:whiteRoundedCornerView];
[cell.contentView sendSubviewToBack:whiteRoundedCornerView];
cell.layer.shouldRasterize = YES;
cell.layer.rasterizationScale = [UIScreen mainScreen].scale;
cell.layer.opaque = YES;
cell.opaque = YES;
}
[cell.contentView addSubview:[self NewsItemThumbnailView:item]];
return cell;
}
Here is the method that returns the thumbnail view of the graphic and text:
- (UIView *) NewsItemThumbnailView:(NewsItem *)item
{
UIView *thumbNailMainView = [[UIView alloc] initWithFrame:CGRectMake(10, 10, 50, 70)];
UIImageView *thumbNail = [[UIImageView alloc] initWithImage:[UIImage imageNamed:item.ThumbNailFileName]];
thumbNail.frame = CGRectMake(10,10, 45, 45);
UILabel *date = [[UILabel alloc] init];
date.frame = CGRectMake(10, 53, 45, 12);
date.text = item.ShortDateString;
date.textAlignment = NSTextAlignmentCenter;
date.textColor = [BVColors WebDarkGrey];
CGFloat fontSize = 10.0;
date.font = [BVFont Museo:&fontSize];
date.opaque = YES;
thumbNail.opaque = YES;
thumbNailMainView.opaque = YES;
[thumbNailMainView addSubview:thumbNail];
[thumbNailMainView addSubview:date];
return thumbNailMainView;
}
The performance problem seems to be when I add the thumbnail view to the cell because when I comment that line out, I don't seem to have it. The thumbnail information is dynamic and will change with each cell. I would appreciate any advice on how I should do this without degrading the performance.
UITableView will call tableView:cellForRowAtIndexPath: each time a cell comes into view, and dequeueReusableCellWithIdentifier: will reuse existing cell objects if they are available. These two facts combine to put you in a scenario where every time you scroll, the same finite number of cell objects end up with an increasing number of subviews.
The proper approach is to create a custom UITableViewCell subclass that has a property for thumbnailView. In the setter for that property, remove the previous thumbnail (if any) and then add the new one to the contentView. This ensures that you'll only ever have one thumbnail subview at any time.
A less optimal approach would be adding a tag to the UIView returned from NewsItemThumbnailView (thumbNailMainView.tag = someIntegerConstant) and then searching for any view with that tag and removing it before adding another:
// remove old view
UIView *oldThumbnailView = [cell.contentView viewWithTag:someIntegerConstant];
[oldThumbnailView removeFromSuperview];
// add new view
[cell.contentView addSubview:[self NewsItemThumbnailView:item]];
I ended up leveraging a solution found on this stackoverflow post:
How should I addSubview to cell.contentView?
Essentially when the cell is first initialized I am setting the view as mentioned by Nishant; however once the cell is reused I am extracting out the items I need to change, such as an UIImageView and then a UILabel. Since these are pointers I can modify just what I need when I need to and the performance is fast again. Here is a abbreviated version of what I did.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *NewsCellIdentifer = #"NewsCellIdentifier";
NewsItem *item = [self.newsArray objectAtIndex:indexPath.row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:NewsCellIdentifer];
UIView *thumbNailMainView = [[UIView alloc] initWithFrame:CGRectMake(10, 10, 50, 70)];
UIImageView *thumbNail;
UIView *textMainView = [[UIView alloc] initWithFrame:CGRectMake(20,20,80,80)];
UILabel *headerLabel = [[UILabel alloc] initWithFrame:CGRectMake(52,-5, 70, 20)];
UILabel *teaserLabel = [[UILabel alloc] initWithFrame:CGRectMake(50,20, 210, 40)];
UIView *newsItemCornerMainView = [[UIView alloc] initWithFrame:CGRectMake(255.7, 55.2, 55, 55)];
UIImageView *cornerIconView;
// If the cell doesn't existing go ahead and make it fresh.
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:NewsCellIdentifer];
// Configure all the various subviews
..... //Sample below
// Make the title view
headerLabel.text = item.Title;
CGFloat textfontSize = 16.0f;
headerLabel.font = [BVFont Museo:&textfontSize];
headerLabel.textColor = [BVColors WebBlue];
headerLabel.textAlignment = NSTextAlignmentLeft;
headerLabel.numberOfLines = 0;
headerLabel.tag = 50;
// Make the Teaser view
teaserLabel.text = item.Teaser;
teaserLabel.numberOfLines = 0;
CGFloat tfontSize = 13.0f;
teaserLabel.textAlignment = NSTextAlignmentLeft;
teaserLabel.textColor = [BVColors WebDarkGrey];
teaserLabel.font = [BVFont HelveticaNeue:&tfontSize];
[teaserLabel sizeToFit];
teaserLabel.tag = 51;
[textMainView addSubview:headerLabel];
[textMainView sendSubviewToBack:headerLabel];
[textMainView addSubview:teaserLabel];
[cell.contentView addSubview:textMainView];
....
}
thumbNail = (UIImageView *) [cell viewWithTag:47];
[thumbNail setImage:[UIImage imageNamed:item.ThumbNailFileName]];
headerLabel = (UILabel *) [cell viewWithTag:50];
headerLabel.text = item.Title;
teaserLabel = (UILabel *) [cell viewWithTag:51];
teaserLabel.text = item.Teaser;
cornerIconView = (UIImageView *) [cell viewWithTag:48];
[cornerIconView setImage:[UIImage imageNamed:item.CornerIconFileName]];
return cell;
}
You should change thumbNailMainView content only everytime but you should not add its content on cell everytime.
So add this line where you are allocating cell
[cell.contentView addSubview:[self NewsItemThumbnailView:item]];
add this inside braces. and then access thumbNailMainView from cell and pass that item data which you need to change for each cell.
Assign a tag to thumbNailMainView and its subview thumbNail then access it as
UIView *_thumbNailMainView = [cell.contentView viewWithTag:_thumbNailMainView_tag];
UIImageView *_thumbNail = [_thumbNailMainView viewWithTag:thumbNail_tag];
_thumbNail.image = [UIImage imageNamed:item.ThumbNailFileName];
Hope it helps you.

UITableViewCell showing double embedded UITextfields

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

UITableView experiences choppy scrolling when cell has a UIImageView subview

This has been driving me crazy for the better part of the day.
I've got a UITableView with UIImageViews. These imageviews load a locally saved PNG-file in the cellForRow-function of the tableview, and this works fine except the tableview will stop scrolling for a fraction of a second when a cell with an image in it scrolls into sight so to speak. I've trawled StackOverflow and google for an answer but I've come up short - so any help will be greatly appreciated.
Here is my code for the CellForRow-function:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"MyIdentifier"];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"MyIdentifier"] autorelease];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
if([currSection isEqualToString:#"composer"]){
MySlide *s = [slidesArray objectAtIndex:indexPath.row];
cell.textLabel.hidden = YES;
UIImageView *whiteView = [[UIImageView alloc] initWithFrame:CGRectMake((projectsTable.frame.size.width/2)-150, 4, 204.8, 153.6)];
if([s.slideImage isEqualToString:#""] || s.slideImage == nil){
//no custom image in this cell - go with default background image
whiteView.image = [UIImage imageNamed:#"cellback2.png"];
whiteView.backgroundColor = [UIColor whiteColor];
}else{
cell.layer.shouldRasterize = YES;
cell.layer.rasterizationScale = [UIScreen mainScreen].scale;
NSData *data = [[NSData alloc] initWithContentsOfFile:s.slideImage];
UIImage *im = [[UIImage alloc] initWithData:data];
whiteView.image = im;
whiteView.image = [self imageWithImage:whiteView.image CovertToSize:CGSizeMake(204.8,153.6)];
whiteView.backgroundColor = [UIColor whiteColor];
}
[cell.contentView addSubview:whiteView];
[whiteView release];
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
There are a couple of changes to be made, first off the UIImageViews should be added when the cell is generated, rather than every time tableView:cellForRowAtIndexPath: is hit (as #Vishy suggests). Secondly you should cache the images you are loading from the documents directory ([UIImage imageNamed:] does this automatically for bundle resources).
#interface MyViewController () {
NSMutableDictionary *_imageCache;
}
#end
#implementation MyViewController
- (void)viewDidLoad {
[super viewDidLoad];
// other viewDidLoad stuff...
_imageCache = [[NSMutableDictionary alloc] init];
}
- (void)viewDidUnload {
[super viewDidUnload];
// other viewDidUnload stuff...
[_imageCache release];
_imageCache = nil;
}
- (void)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"MyIdentifier"];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"MyIdentifier"] autorelease];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
UIImageView *whiteView = [[UIImageView alloc] initWithFrame:CGRectMake((projectsTable.frame.size.width/2)-150, 4, 204.8, 153.6)];
whiteView.tag = 111;
whiteView.backgroundColor = [UIColor whiteColor];
[cell.contentView addSubview:whiteView];
[whiteView release];
cell.accessoryType = UITableViewCellAccessoryNone;
cell.textLabel.hidden = YES;
}
UIImageView* iView = (UIImageView*) [cell.contentView viewWithTag:111];
if([currSection isEqualToString:#"composer"]) {
MySlide *s = [slidesArray objectAtIndex:indexPath.row];
if([s.slideImage isEqualToString:#""] || s.slideImage == nil) {
//no custom image in this cell - go with default background image
iView.image = [UIImage imageNamed:#"cellback2.png"];
}
else {
cell.layer.shouldRasterize = YES;
cell.layer.rasterizationScale = [UIScreen mainScreen].scale;
// use the image path as the cache key
UIImage *theImage = [_imageCache objectForKey:s.slideImage];
if (theImage == nil) {
// load the image and save into the cache
theImage = [UIImage imageWithContentsOfFile:s.slideImage];
theImage = [self imageWithImage:theImage CovertToSize:CGSizeMake(204.8, 153.6)];
[_imageCache setObject:theImage forKey:s.slideImage];
}
iView.image = theImage;
}
}
}
#end
As a general rule, tableView:cellForRowAtIndexPath: is a method you need to get out of fast, so loading images from disk should be avoided wherever possible.
Change the code as per below...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"MyIdentifier"];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"MyIdentifier"] autorelease];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
UIImageView *whiteView = [[UIImageView alloc] initWithFrame:CGRectMake((projectsTable.frame.size.width/2)-150, 4, 204.8, 153.6)];
whiteView.tag = 111;
whiteView.backgroundColor = [UIColor whiteColor];
[cell.contentView addSubview:whiteView];
[whiteView release];
cell.accessoryType = UITableViewCellAccessoryNone;
cell.textLabel.hidden = YES;
}
UIImageView* iView = (UIImageView*) [cell.contentView viewWithTag:111];
if([currSection isEqualToString:#"composer"])
{
MySlide *s = [slidesArray objectAtIndex:indexPath.row];
if([s.slideImage isEqualToString:#""] || s.slideImage == nil)
{
//no custom image in this cell - go with default background image
iView.image = [UIImage imageNamed:#"cellback2.png"];
}
else
{
cell.layer.shouldRasterize = YES;
cell.layer.rasterizationScale = [UIScreen mainScreen].scale;
iView.image = [UIImage imageWithContentsOfFile:s.slideImage];
iView.image = [self imageWithImage:iView.image CovertToSize:CGSizeMake(204.8,153.6)];
}
}
}
There is also a delay the first time each UIImage is displayed. See this post for details on prompting the work at cache time rather than display time:
Setting image property of UIImageView causes major lag

UITableview dequeueReusableCellWithIdentifier and scroll-freezing issues

So I have some issues with my tableview. I have a custom label that I put into a tableview cell to add a little better graphics than the standard UItableviewcell. However, I was running into my first problem,
the text labels that I had on the cells were changing with and over writing each other upon scrolling, only when the cells had moved off screen and then came back. Upon some research I found that maybe it had something to do with dequeueReusableCellWithIdentifier: so I adjusted my code. this is where problem two comes in.
When I load the table everything is in its right place, correct looking and all. However when I start to scroll down I can get to all of my cells except the last one, it will go to the very bottom of the 8th cell and freeze, but I should have 9 cells loaded.
I am quite confused by some of this, could anyone provide some code or guidance to help me along?
Thanks.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"Run");
CoCoachAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
static NSString *CellIdentifier = #"Cell";
UILabel *label;
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
NSArray *keys = [[appDelegate rowersDataStore] allKeys];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
// Configure the cell...
label = [[[UILabel alloc] initWithFrame:CGRectMake(20, 15, cell.bounds.size.width - 10, 30)] autorelease];
label.font = [UIFont boldSystemFontOfSize:16];
label.backgroundColor = [UIColor clearColor];
label.shadowColor = [UIColor colorWithWhite:1.0 alpha:0.5];
label.shadowOffset = CGSizeMake(0,1);
label.textColor = [UIColor colorWithRed:0x4c/255.0 green:0x4e/255.0 blue:0x48/255.0 alpha:1.0];
switch (indexPath.section) {
case 0:
label.frame = CGRectMake(0, 15, cell.bounds.size.width - 10, 30);
label.textAlignment = UITextAlignmentCenter;
break;
case 1:
label.textAlignment = UITextAlignmentLeft;
UIImage *accessoryImage = [UIImage imageNamed:#"content_arrow.png"];
UIImageView *accessoryView = [[UIImageView alloc] initWithImage:accessoryImage];
cell.accessoryView = accessoryView;
[accessoryView release];
break;
}
UIImageView *imgView = [[UIImageView alloc] initWithFrame:cell.frame];
UIImage* img = [UIImage imageNamed:#"odd_slice.png"];
imgView.image = img;
cell.backgroundView = imgView;
[imgView release];
//Selected State
UIImage *selectionBackground = [UIImage imageNamed:#"row_selected.png"];
UIImageView *selectionView = [[UIImageView alloc] initWithFrame:cell.frame];
selectionView.image = selectionBackground;
cell.selectedBackgroundView = selectionView;
[selectionView release];
}
switch (indexPath.section) {
case 0:
[label setText:#"Click to add new rower"];
break;
case 1:
[label setText:[[[appDelegate rowersDataStore] objectForKey:[keys objectAtIndex:indexPath.row]] objectForKey:#"Name"]];
break;
}
//Adds Text
[cell addSubview:label];
return cell;
}
I see several issues here. First, the general structure of this method should be...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
// Attempt to dequeue the cell
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// If cell does not exist, create it, otherwise customize existing cell for this row
if (cell == nil) {
// Create cell
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
// Configure cell:
// *** This section should configure the cell to a state independent of
// whatever row or section the cell is in, since it is only executed
// once when the cell is first created.
}
// Customize cell:
// *** This section should customize the cell depending on what row or section
// is passed in indexPath, since this is executed every time this delegate method
// is called.
return cell;
}
Basically, UITableView uses a single UITableViewCell instance to draw every cell in the table view. So, when you first create this cell, you should configure it to a state that is common to all cells that will use this instance, independent of whatever row or section is passed in indexPath. In your example, this involves creating the label, image, and background image instances and adding them as subviews to the cell.
Once the cell is created (aka outside the if (cell == nil) statement), you should customize its properties according to how the cell should look for the specific row and section contained in indexPath. Since you want to access your custom label in this part of the code, I assigned a tag value to it so that we can access it beyond the code segment where it was created using viewWithTag:. Once we have the label, we can customize it according to the section as well as do anything else we want, such as customize the accessory view.
I slightly modified/cleaned up your code below. This is by far not the most efficient or elegant way to do what you want to do, but I was trying to keep as much of your code as possible. I haven't tested this, but if you try it it should work:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"Run");
CoCoachAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
NSArray *keys = [[appDelegate rowersDataStore] allKeys];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
// Configure the cell...
UILabel *label;
label = [[[UILabel alloc] initWithFrame:CGRectMake(20, 15, cell.bounds.size.width - 10, 30)] autorelease];
label.font = [UIFont boldSystemFontOfSize:16];
label.opaque = NO;
label.backgroundColor = [UIColor clearColor];
label.shadowColor = [UIColor colorWithWhite:1.0 alpha:0.5];
label.shadowOffset = CGSizeMake(0,1);
label.textColor = [UIColor colorWithRed:0x4c/255.0 green:0x4e/255.0 blue:0x48/255.0 alpha:1.0];
label.tag = 100;
[cell addSubview:label];
[label release];
UIImageView *imgView = [[UIImageView alloc] initWithFrame:cell.frame];
UIImage* img = [UIImage imageNamed:#"odd_slice.png"];
imgView.image = img;
cell.backgroundView = imgView;
[imgView release];
//Selected State
UIImage *selectionBackground = [UIImage imageNamed:#"row_selected.png"];
UIImageView *selectionView = [[UIImageView alloc] initWithFrame:cell.frame];
selectionView.image = selectionBackground;
cell.selectedBackgroundView = selectionView;
[selectionView release];
}
UILabel *lbl = (UILabel *)[cell viewWithTag:100];
switch (indexPath.section) {
case 0:
cell.accessoryView = nil;
lbl.frame = CGRectMake(0, 15, cell.bounds.size.width - 10, 30);
lbl.textAlignment = UITextAlignmentCenter;
[label setText:#"Click to add new rower"];
break;
case 1:
UIImage *accessoryImage = [UIImage imageNamed:#"content_arrow.png"];
UIImageView *accessoryView = [[UIImageView alloc] initWithImage:accessoryImage];
cell.accessoryView = accessoryView;
[accessoryView release];
lbl.frame = CGRectMake(20, 15, cell.bounds.size.width - 10, 30);
lbl.textAlignment = UITextAlignmentLeft;
[lbl setText:[[[appDelegate rowersDataStore] objectForKey:[keys objectAtIndex:indexPath.row]] objectForKey:#"Name"]];
break;
}
return cell;
}

Transparency between UITableViewCells

I want to have transparency between UITableViewCells. Space between the cells.
I user custom created cells and for setting a background i use this code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CustomCell = #"CustomBookingCell";
currentBooking = [arrayBookings objectAtIndex:indexPath.row];
CustomBookingCell *cell = (CustomBookingCell *)[tableView dequeueReusableCellWithIdentifier:CustomCell];
if (cell == nil) {
UIViewController *c = [[UIViewController alloc] initWithNibName:#"CustomBookingCell" bundle:nil];
cell = (CustomBookingCell *)c.view;
[ c release ];
}
bookingImage = [[UIImageView alloc] initWithImage:
[UIImage imageNamed:currentBooking.imageSource]];
[cell.imageForBooking addSubview:bookingImage];
cell.selectionStyle = UITableViewCellSelectionStyleGray;
cell.contentView.backgroundColor = [UIColor clearColor];
UIView* backgroundView = [[UIView alloc] initWithFrame:CGRectZero];
UIImage* bgImage = [UIImage imageNamed:#"Background_300_82.png"];
UIColor *bgColor = [[UIColor alloc] initWithPatternImage: bgImage];
backgroundView.backgroundColor = bgColor;
cell.backgroundView = backgroundView;
cell.label.text = currentBooking.title;
[bookingImage release];
[bgColor release];
[backgroundView release];
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 90;
}
The height of the cell is 10 pixels higher that the tableCellBg.png.
My background view has also a image as background (this background is supposed to be shown between the cells of course).
So I tried to add 10 pixels with transparency to my tableCellBg.png in the bottom to fix this. But the space between the cells is black. I can't see the view background between my cells.
What shall I do? Do I have to create a UIView in cellForRowAtIndexPath with the height of the tableCellBg.png and then add the Custom UITableViewCell as subview to the created UIView with a less higher height?
Or is there a much more simplyfied way to accomplish this?
Your table view needs a clear background colour. For example
myTableView.backgroundColor = [UIColor clearColor];
I solved it by using another method to add the background image to the UITableViewCell:
UIImage *image = [UIImage imageNamed:#"ny_bg_event.png"];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
imageView.frame = CGRectMake(0, 0, 300, 84);
cell.backgroundView = imageView;
cell.backgroundColor = [UIColor clearColor];
[imageView release];
[cell setFrame:CGRectMake(0, 0, 300, 84)];
cell.contentView.backgroundColor = [UIColor clearColor];
Instead of creating a UIView I just used a UIImageView instead.