I want to toggle UITableViewCell image - cell.imageView.image. (eg. Red <--> Green)
If the current image is green, the image suppose to change to Red when the user click the UITableViewCell.
Once I set the image
cell.imageView.image = [UIImage imageNamed:#"Green.png"];
How to detect which image is the cell currently using?
Thanks for any help!
Set the tag on the imageView itself:
#define IMAGE_TAG_GREEN 50
#define IMAGE_TAG_RED 51
-(UITableViewCell*) tableView:(UITableView*) tableView cellForRowAtIndexPath:(NSIndexPath *) indexPath {
static NSString *CELL_ID = #"some_cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CELL_ID];
if(cell == nil) {
//do setup here...
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CELL_ID] autorelease];
cell.imageView.tag = //some logic here...
}
if(cell.imageView.tag == IMAGE_TAG_GREEN) {
//...
} else {
//...
}
return cell;
}
Since tag is an inherited property from UIView, you cannot use it with UIImage itself, but you can use it with UIImageView
It's a bit crude, but you should be able to set up an if statement like the following:
if ([cell.imageView.image isEqual:[UIImage imageNamed:#"Green.png"]]) {
// image is green;
} else {
// image is red;
}
I tested it out just to make sure and it works fine
I believe just add a Boolean expression and make it TRUE if it is green and FALSE if it is red.
Make this boolean expression extern type so that this could be a global expression.
Set the boolean value on clicking the image.
I believe this would be of some help.
I'm new to this - but I imagine you could use an if/then statement.
If (cell.imageView.image = [UIImage imageNamed:#"Green.png"]) {
cell.imageView.image = [UIImage imageNamed:#"Green.png"];
} else
{
cell.imageView.image = [UIImage imageNamed:#"Red.png"];
}
Or you could go really fancy and use the ternary operator. Something like the following (note the code below is probably wrong - but should hopefully get you started!):
cell.imageView.image = ([UIImage imageNamed:#"Green.png"]) ?
cell.imageView.image = [UIImage imageNamed:#"Green.png"]; :
cell.imageView.image = [UIImage imageNamed:#"Red.png"];
Let us know how you go with this.
Kolya
Related
This piece gives strange results in my TableView. I want the UIImage displayed for the cells where the reprecented objects value for key "Marked" = "Yes".
What is the correct code for this?
if ([[[sortedObjects objectAtIndex: indexPath.row] valueForKey:#"Marked"] isEqual:#"Yes"])
{
cell.markedImageView.image = [UIImage imageNamed:#"markedItem.png"];
}
The problem is that you need to clear the imageView image each time the cell is reused.
- (void)configCell:(MyCustomCell *)cell atIndexPath:(NSIndexPath)indexPath
{
cell.markedImageView.image = nil;
// configure cell normally
if ([[[sortedObjects objectAtIndex: indexPath.row] valueForKey:#"Marked"] isEqual:#"Yes"])
{
cell.markedImageView.image = [UIImage imageNamed:#"markedItem.png"];
}
}
I am trying to import an image in just cell number 1 and 2 ! , but I the result is my image will show in last cell ! I do not know why !! this is the picture that shows my situation :
// Configure the cell.
NSUInteger row = [indexPath row];
cell.textLabel.text = [titles objectAtIndex:row];
cell.detailTextLabel.text = [subtitle objectAtIndex:row];
switch (indexPath.row) {
case 0:
cell.imageView.image = [UIImage imageNamed:#"new.png"];
break;
case 1:
cell.imageView.image = [UIImage imageNamed:#"new.png"];
break;
}
return cell;
}
Either in your tableView:cellForRowAtIndexPath: set the imageView's image to nil before conditionally checking to set the new image or implement prepareForReuse on your cell subclass and set all of the cell's views values to nil.
This will ensure that reused cells are 'clean' before they're brought on screen.
Alternatively you could edit your switch to look like:
switch (indexPath.row) {
case 0:
cell.imageView.image = [UIImage imageNamed:#"new.png"];
break;
case 1:
cell.imageView.image = [UIImage imageNamed:#"new.png"];
break;
default:
cell.imageView.image = nil;
break;
}
The first thing that it makes me think of is that the first cell gets somehow recycled and used for the last cell. You can try to set the image view to nil for every cell and set it just in the first two cells. Should be something like this:
cell.imageView.image = nil;
Hope it helps! ;D
You might have used "static NSString *reuseIdentifier = #"Identifier" ", this means that all cells will be considered same by this reuseIdentifier. Only visible cells would be different so for example, if there are 5 visible cells on device, then only 5 new cells would be allocated for cell, and then if you scroll down or up, these 5 cells will be reused if you specified reuseIdentifier statically.
I would suggest to make cell uniquely identified by reuseIdentifier, change the above line to "NSString *reuseIdentifier = [NSString stringWithFormat:#"cell%d",indexPath.row]" This would solve the issue.
Hope this helps.
Your cells are reused by the tableview to save memory. You have to tell the cell not to use an image on every other cell. Modify the switch command like this:
switch (indexPath.row) {
case 0:
cell.imageView.image = [UIImage imageNamed:#"new.png"];
break;
case 1:
cell.imageView.image = [UIImage imageNamed:#"new.png"];
break;
default:
cell.imageView.image = nil;
break;
}
Sandro Meier
try this it might help you
case 0:
cell.imageView.image = [UIImage imageNamed:#"new.png"];
break;
case 1:
cell.imageView.image = [UIImage imageNamed:#"new.png"];
break;
default
cell.imageView.image=nil;
I've got a custom UITableViewCell class whose model object performs an asynchronous download of an image which is to be displayed in the cell. I know I've got the outlets connected properly in IB for WidgetTVC, I know that image data is being properly returned from my server, and I've alloc/init'd the widget.logo UIImage too. Why is the image always blank then in my tableViewCell? Thanks in advance.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
Widget *theWidget = [widgetArray objectAtIndex:indexPath.row];
static NSString *CellIdentifier = #"WidgetCell";
WidgetTVC *cell = (WidgetTVC*)[self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil)
{
[[NSBundle mainBundle] loadNibNamed:#"WidgetTVC" owner:self options:nil];
cell = self.widgetTVC;
self.widgetTVC = nil;
}
[cell configureWithWidget:theWidget];
return cell;
}
In my WidgetTVC class, I have the following method:
- (void)configureWithWidget:(Widget*)aWidget {
self.widget = aWidget;
self.nameLbl.text = aWidget.name;
[self.logoIvw setImage:aWidget.logo]; // logoIvw is the image view for the logo
}
Finally- I've got the callback method that sets the logo UIImage property on the Widget model object asynchronously (simplified):
(void)didReceiveImage:(ASIHTTPRequest *)request {
// I pass a ref to the Widget's logo UIImage in the userInfo dict
UIImage *anImage = (UIImage*)[request.userInfo objectForKey:#"image"];
UIImage *newImage = [UIImage imageWithData:[request responseData]];
anImage = newImage;
}
In didReceiveImage:, you're only modifying the local pointer anImage. You need to set the image property of your UIImageView in order to update what gets displayed. Instead of stashing a reference to your widget's UIImage, pass a reference to the UIImageView, and in didReceiveImage: do something like
UIImageView *imageView = (UIImageView*)[request.userInfo objectForKey:#"imageView"];
UIImage *newImage = [UIImage imageWithData:[request responseData]];
imageView.image = newImage;
Perhaps the best solution would be to have your model object have the image as a property and the display object subscribe to the image property's changes through KVO and update itself whenever the image property changes.
OK- there were a couple things wrong here. Thanks to bosmacs and Ed Marty as both of your comments were used to get to the solution.
First, I added a method to the Widget object to get the logo asynchronously:
- (void)asyncImageLoad {
...
// logo is a UIImage
[AsyncImageFetch fetchImage:&logo fromURL:url];
}
And my own AsyncImageFetch class looks like this:
+ (void)fetchImage:(UIImage**)anImagePtr fromURL:(NSURL*)aUrl {
ASIHTTPRequest *imageRequest = [ASIHTTPRequest requestWithURL:aUrl];
imageRequest.userInfo = [NSDictionary dictionaryWithObject:[NSValue valueWithPointer:anImagePtr] forKey:#"imagePtr"];
imageRequest.delegate = self;
[imageRequest setDidFinishSelector:#selector(didReceiveImage:)];
[imageRequest setDidFailSelector:#selector(didNotReceiveImage:)];
[imageRequest startAsynchronous];
}
+ (void)didReceiveImage:(ASIHTTPRequest *)request {
UIImage **anImagePtr = [(NSValue*)[request.userInfo objectForKey:#"imagePtr"] pointerValue];
UIImage *newImage = [[UIImage imageWithData:[request responseData]] retain];
*anImagePtr = newImage;
}
Finally, per Ed, I added this to the configureWithWidget method that helps set up my WidgetTVC:
[aCoupon addObserver:self forKeyPath:#"logo" options:0 context:nil];
And when a change is observed, I update the imageView and call [self setNeedsDisplay]. Works like a charm. Any way I can give you both points?
i'm using a default style table (UITableViewCellStyleSubtitle)
i want to add more then one detailTextLabel in each row,
how can i customize it?
code:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:CellIdentifier] autorelease];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
// Leave cells empty if there's no data yet
if (nodeCount > 0)
{
// Set up the cell...
ARecord *aRecord = [self.entries objectAtIndex:indexPath.row];
cell.textLabel.text = aRecord.lDate;
cell.detailTextLabel.text = aRecord.WNum;
// Only load cached images; defer new downloads until scrolling ends
//(!aRecord.appIcon) - use icon
if (!aRecord.appIcon)
{
if (self.tableView.dragging == NO && self.tableView.decelerating == NO)
{
[self startIconDownload:aRecord forIndexPath:indexPath];
}
// if a download is deferred or in progress, return a placeholder image
cell.imageView.image = [UIImage imageNamed:#"Placeholder.png"];
}
else
{
cell.imageView.image = aRecord.appIcon;
}
}
return cell;
}
The best way of doing this is to add a UILabel to the cell.contentView. You would do this when you initially create the cell. I've found two things to be especially helpful: to lay out the label on a table cell in a throwaway document in Interface Builder to determine the initial frame. It's also especially helpful to set the autoresizingMask so that the label will be resized appropriately when the cell is resized (due to autorotation, going into edit mode, etc.).
Finally, you'll need to set the table view's rowHeight to a higher value to accommodate the larger cells, otherwise you'll end up with overlapping cells.
Also, set a tag on your label to make it easy to retrieve with viewWithTag: when you go to update the text.
You could add the labels to cell.contentView.
I use datamodel to store 2 objects : Video, Images.
Video contain just string attributes and Images have 2 "Binary data" attributes.
At the start the 2 binary data attributes was in the video object.
But all videos are loading during initialization of UITableView.
For 400 videos binary data represent 20 Mo, so imagine with 4000 videos...
Now with 2 objects the UITableView loading work well.
I load binary data when it's necessary in the method : tableView:cellForRowAtIndexPath
But now more I scroll into the list, more the memory grow up :(
look at my method :
- (UITableViewCell *)tableView:(UITableView *)myTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"videoCell";
Video *theVideo = (Video *)[[self fetchedResultsController] objectAtIndexPath:indexPath];
VideoCellViewController *cell = (VideoCellViewController *)[myTableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
[[NSBundle mainBundle] loadNibNamed:#"VideoCellView" owner:self options:nil];
cell = editingTableViewCell;
self.editingTableViewCell = nil;
}
cell.video = theVideo;
return cell;
}
And the method setvideo in VideoCellViewController
- (void)setVideo:(Video *)newVideo {
if (newVideo != video) {
[video release];
video = [newVideo retain];
}
NSData *imageData = [video.allImages valueForKey:#"thumbnailImage"];
UIImage *uiImage = [[UIImage alloc] initWithData:imageData];
smallImage.image = uiImage;
nameLabel.text = video.displayName;
[uiImage release];
}
Even without set the smallImage, I have memory trouble.
If I load the image object, it's never release.
I try a lot of solution to release memory without succes...( didTurnIntoFault, release, CFRelease...)
In performance tool, I can see my binary data as CFData.
I use a lot iPhoneCoreDataRecipes and PhotoLocations sample.
I need help to clean my memory ;)
Thanks
Samuel
Clearly there is something going on with your table cell creation logic. Let's take a look at a typical cellForRow delegate handler first..
static NSString *MyIdentifier = #"MyIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:MyIdentifier] autorelease];
}
// do stuff with cell
return cell;
Here we see we are
trying to get a reusable cell
if that fails (nil) create a new one and pass the reusable id to the ctor
then do stuff with the cell (new or existing) and return it
If you do not key the cell for reuse in the table view, you will always get a 'nil' cell returned from the dequeue, hence the need to create new cells every time. This will cause memory to continue to grow as you scroll around, but stay fairly flat when idle.
EDIT:
Assuming your cell is fine, then you need to narrow down if it's the video data or the image data that is leaking. What is smallImage? And are you sure you do not want to do everything only when the video is new?
- (void)setVideo:(Video *)newVideo {
if (newVideo != video) {
[video release];
video = [newVideo retain];
NSData *imageData = [video.allImages valueForKey:#"thumbnailImage"];
UIImage *uiImage = [[UIImage alloc] initWithData:imageData];
smallImage.image = uiImage;
nameLabel.text = video.displayName;
[uiImage release];
}
}