I have a UICollectionView where I display a grid of images downloaded from the Internet. I am using SDWebImage to load the images. The problem I am facing is that, when I scroll through the UICollectionView, sometimes the cells repeat themselves, displaying the same image. But when the cell is scroll out of view and then brought back, it has the right image set.
-(UICollectionViewCell*) collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
NSString *CellIdentifier = #"Gallery_Cell";
GalleryCell *cell;
if (cell==nil) {
cell= (GalleryCell *)[self.flowCollection dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath];
ImageItem *dets = [self.imageList objectAtIndex:indexPath.row];
NSURL *mainImageURL = [NSURL URLWithString:dets.smallImageURL];
cell.image.contentMode = UIViewContentModeScaleAspectFill;
cell.image.clipsToBounds = YES;
[cell.image setImageWithURL:mainImageURL placeholderImage:nil];
}
return cell;
}
Has this happened to anyone else? Would highly appreciate any pointers.
On GalleryCell.m you need to add prepareForReuse method and there nullify the _image variable (assuming that you have a image #property in the cell):
- (void)prepareForReuse {
[super prepareForReuse];
[self setHighlighted:NO];
_image = nil;
}
The following is stated in the "UICollectionView Class Reference":"
If you registered a class for the specified identifier and a new cell must be created, this method initializes the cell by calling its initWithFrame: method. For nib-based cells, this method loads the cell object from the provided nib file. If an existing cell was available for reuse, this method calls the cell’s prepareForReuse method instead."
Do you have a prepareForReuse method for your GalleryCell cell class?
you cell class should be a subclass of UICollectionReusableView Class. And check it.
I ended up using “didEndDisplayingCell” method of UICollectionView and ending the current Image download and setting the image to nil. This worked perfectly and there was no more “shuffling” or repetition of images! :)
use this method this vl definitely work 100%.
- (void)collectionView:(UICollectionView *)collectionView didEndDisplayingCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath;
{
GalleryCell *cell1 = (GalleryCell*)[_resumeCollectionView cellForItemAtIndexPath:indexPath];
cell1= nil;
}
-(UICollectionViewCell*) collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
NSString *CellIdentifier = #"Gallery_Cell";
GalleryCell *cell;
if (cell==nil) {
cell= (GalleryCell *)[self.flowCollection dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath];
ImageItem *dets = [self.imageList objectAtIndex:indexPath.row];
NSURL *mainImageURL = [NSURL URLWithString:dets.smallImageURL];
[cell.image setImage:[UIImage new]];
cell.image.contentMode = UIViewContentModeScaleAspectFill;
cell.image.clipsToBounds = YES;
[cell.image setImageWithURL:mainImageURL placeholderImage:nil];
}
return cell;
}
Since the cells are being reused, you must set their contents unconditionally in cellForIndexPath:. Your code as it is sets the images eventually, but it leaves the chance for the images to be temporarily left as old values -- values set before they were reused.
A quick solution is (probably) to provide that setImageWithURL call with a placeholder image. I don't know the SDImage library, but it's a good guess that it immediately sets an imageView's image to the placeholder image if one is provided.
If you don't have or don't want a placeholder image, you can implement prepareForReuse in your UICollectionViewCell subclass and clear the imageView there.
Related
I have added another UICollectionViewCell onto my UICollectionView as shown:
Each are connected to a different class the Yellow one is connected to a class called ImageCell and the Blue one is connected to a class called TwitterCell. The Image Cell is supposed to Display an Instagram picture with the UIImageView (Which BTW works fine right now). However I want to add other cells under the TwitterCell which is supposed to show Twitter Tweets of the user with the UILabel. Here is my code right now:
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
ImageCell *cell = (ImageCell *)[collectionView dequeueReusableCellWithReuseIdentifier:#"imageCell"
forIndexPath:indexPath];
NSURL *url = [self imageUrlForEntryAtIndexPath:indexPath];
//NSLog(#"%#", url);
[cell.imageView setImageWithURL:url];
cell.backgroundColor = [UIColor whiteColor];
TwitterCell *tweetCell = (TwitterCell *)[collectionView dequeueReusableCellWithReuseIdentifier:#"twitterCell" forIndexPath:indexPath];
return cell;
return tweetCell;
}
Here is the end image of what I want (keep in mind everything is ordered by time posted):
Remember to registerClass:forCellWithReuseIdentifier: in order to get the dequeue to work properly. Also, you can only answer one cell in cellForItemAtIndexPath: check to see if the row is even or odd to decide which kind of cell to dequeue, then initialize the contents only of that cell.
I need to allow my users to scroll through a list of thumbnails in the documents directory on an iPad application. When they tap on one of the thumbnails, I need to know which one was tapped (or have it call a method, which is basically the same thing.)
I know how to put the thumbnails in the documents directory, and how to read them from there. But I’m not sure which widget is best for displaying the content. Is it UITableView? CCScrollLayer? CCMenuAdvanced? Something else?
CCScrollLayer doesn't work as well as UIScrollView.
I use the view to CCdirector for add UIkit.
UIScrollView *scrollView = [UIScrollView alloc] init];
[[[CCDirector sharedDirector] view] addSubview:scrollView];
or add UITableView.
Take all the paths for thumbnails in one array, lets call pathsArray
NSArray *pathsArray = [seld getPathsForAllImages];
Now implement UITableViewDataSource and UITableViewDelegate:
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [pathsArray count];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIdentifier];
}
NSString *pathForImage = [pathsArray objectAtIndex:indexPath.row];
cell.imageView.image = [UIImage imageWithContentsOfFile:pathForImage];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *pathForImage = [pathsArray objectAtIndex:indexPath.row];
}
I've had all kinds of problems with overlaying a UIScrollView on a cocos2d project. Even with all the suggested hacks, if a single frame takes too long in cocos2d, the UIScrollView just stops working right. I would suspect that would happen with a UITableView as well.
To solve my own problems, I created a custom ScrollNode class. It's really easy to use:
// create the scroll node
ScrollNode *scrollNode = [ScrollNode nodeWithSize:CGSizeMake(size.width, size.height)];
[self addChild:scrollNode];
// Generate some content for the scroll view
// add it directly to scrollView, or to the built in menu (scrollView.menu)
[scrollNode.menu addChild:yourMenuItem];
// Set the content rect to represent the scroll area
CGRect contentRect = [scrollNode calculateScrollViewContentRect];
[scrollNode setScrollViewContentRect:contentRect];
In my application i need to display multiple images in a UITableView,so i've already searched a lot in the web for the proper way to load large images to UITableViewCells,to be more clearly i'll divide the procedure that my app execute:
Download images asynchronous;
Save them to NSHomeDirectory();
=> Thins part is working perfectly.
The problem is,how to display the images in the UITableViewCell,i've already tried to add UIImageView's to the cell contentView but the scrolling performance were a bit affected,i've searched on Apple guides and i believe the correct way is adding UIImageView's to the cell and loading the images from NSHomeDirectory(),so:
What's the best way to customize a UITableViewCell and add the UIImageView's(302x302px) to it?
To get the best scroll performance, you must draw the content of the UITableViewCell yourself.
Loren Brichter, the author of the Tweetie app (now the official Twitter app), wrote a very famous blog post on this. Sadly, this blog post has been deleted.
This article may help you, though. It explains the fast scrolling, it has examples and it has a video to a presentation from Loren Brichter.
Basically, what you want to do is to subclass UITableViewCell and override the drawRect:method. To show an image, you would do something like the following:
- (void)drawRect:(CGRect)rect
{
[myImage drawAtPoint:CGPointMake(10, 10)];
}
This way you avoid to layout a lot of subviews.
I have the same question.
I'm doing the following:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString* CustomCellIdentifier = #"CustomCellIdentifier";
CustomCell* cell = [tableView dequeueReusableCellWithIdentifier:CustomCellIdentifier];
if (cell == nil) {
cell = [[CustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CustomCellIdentifier];
}
// add subview to cell
if (cell.customView == NULL) {
cell.customView = [[CustomView alloc] initWithFrame:cell.frame];
[cell.contentView addSubview:cell.customView];
}
// bind cell data
return cell;
}
Firstly, you need to create a custom cells for UITableView & keep going through following points.
set height of each row to 302 pixels as
-(CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 302.0;
}
Use following code to create UIImageView at each cell of table
-(UITableViewCell*) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:#"cell"];
const NSInteger IMAGE_VIEW_TAG=1001;
UIImageView *imageView;
if(cell==nil)
{
cell=[[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"] autorelease];
cell.accessoryType=UITableViewCellAccessoryDisclosureIndicator;
imageView =[[[UIImageView alloc] initWithFrame:CGRectMake(10, 0, 302, 302)] autorelease];
imageView.tag=IMAGE_VIEW_TAG;
imageView.contentMode=UIViewContentModeScaleAspectFit;
[cell.contentView addSubview:imageView];
}
imageView=(UIImageView*)[cell.contentView viewWithTag:IMAGE_VIEW_TAG];
[imageView setImage:[UIImage imageNamed:#"image.png"];
return cell;
}
set number of rows you want to display
-(NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 5;
}
dont forget to add TableView delegate and data source , UITableViewDelegate and UITableViewDataSource
I have this problem when deploying my application on iphone, which wasn't detected on the simulator.
this the code of the cellforrow...
- (UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"beginning cellforRowAtIndexPath for section %d, and cell %d",[indexPath indexAtPosition:0],[indexPath indexAtPosition:1]);
static NSString *MyIdentifier = #"MyIdentifier";
NSString *fieldTitle;
NSString*fieldDescription;
[_stopWatch start];
[PersonalSection GetField:&fieldTitle AndValue:&fieldDescription UsingIndexPath:indexPath AndPersonalInformation:_personalInfo];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil) {
[[NSBundle mainBundle] loadNibNamed:#"ViewContent" owner:self options:nil];
cell = tvCell;
self.tvCell=nil;
((UILabel*) [cell.contentView viewWithTag:1]).layer.cornerRadius=11;
((UILabel*) [cell.contentView viewWithTag:2]).layer.cornerRadius=11;
}
UILabel*mainLabel=(UILabel*) [cell.contentView viewWithTag:1];
mainLabel.text=fieldTitle;
//mainLabel.textColor = [UIColor colorWithRed:0.745 green:0.116 blue:0.176 alpha:1.0];
UILabel*detailLabel=(UILabel*)[cell.contentView viewWithTag:2];
detailLabel.text=fieldDescription;
[_stopWatch stop];
NSLog(#"---------End cellforRowAtIndexPath");
return cell;
}
the rest is for sections and it's like return 3 or 5 no real bottleneck there.
so i'm wondering what's slowing it so much.
now the data fetching "[PersonalSection GetField:&fieldTitle..." is rather fast, it takes on the iphone maximum 0.1 ms. The problem is somewhere else, i'm guessing there's a way for optimizing this code, and i'm wondering about the custom cell influence it's only a cell with label and textfield linked to this ViewController.
Any ideas.
When you create the cell you're setting the identifier to #"cell" but when you dequeue it you're looking for #"MyIdentifier". It looks like you're recreating the cell every time though this.
Ok, the main performance issue was rounding the corners of the subviews of the contentview.
using QuartzCore:
#import <QuartzCore/QuartzCore.h>
((UILabel*) [cell.contentView viewWithTag:1]).layer.cornerRadius=11;
I removed those and decreased the sizes of the controls to fit inside the cell of a sectioned table. and now they look round but the textfield and label are not.
this has fixed my scrolling performance noticeably.
Thank you all for your help.
i have set up a tableview with custom cells. customCell is a class.
heres the code for a more accurate view:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSManagedObject *object = (NSManagedObject *)[entityArray objectAtIndex:indexPath.row];
NSString *cellIdentifier = [NSString stringWithFormat:#"asd%d", indexPath.row];
customCell *cell = [[tableView dequeueReusableCellWithIdentifier:cellIdentifier] autorelease];
//i tried setting a tag but dunno how to call it afterwards
[cell setTag:indexPath.row];
if (cell == nil) {
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"customCell" owner:self options:nil];
cell = [topLevelObjects objectAtIndex:0];
}
if (cell.imagen != nil) {
[[cell imageView] setImage:[cell imagen]];
} else { /* setup image... */ }
}
-(void) webImageReady:(WebImage *)downloadedImage imageView:(UIImageView *)imageView cellTag:(NSInteger *)cTag
{
// This is the part where i want to access cell.imagen, this is actually wrong...
[[[imageView.superview viewWithTag:cTag] imagen] setImagen:downloadedImage.Image];
[imageView setImage:downloadedImage.Image];
}
Ok. now i want to access (reference) the cell.imagen property from a method outside cellForRowAtIndexPath, more precisely at a selector for a download finished (delegated)
Thanks in advance!
Do it inside cellForRowAtIndexPath if the image is downloaded, and on successful download of the image do [tableview setNeedsDisplay]
You shouldn't refer to the cell outside the cell creation method, you should consider the case the cell was rendered but while getting the image was scrolled out the dealloced or even reused for another cell, one way to solve it is to have image view array or something similar.
I think you should try using a third party lib that already doing it(among other things) called Three20. It have an object call TTImageView that gets a URL and loads it in the background, it solves all of the cases along with optimized caching