My aim is to display a row of lazy loaded thumbnails (number not known) using a UICollectionView
, the user can then scroll the thumbnails horizontally.
I am using the code below to achieve close to what I am after but I am getting an error.
The first 4 thumbnails load okay but as you scroll the thumbnails start to get drawn on top of each other and in random orders.
I am trying to get it so that it achieves the following:
Item 1 ----- Item 2 ----- Item 3 ---- Item 4
I would like it so that the cells are only drawn once similar to what you would get when you use a UITableView
. I only want the UICollectionView
to reload the data when I call for it.
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell *cell=[collectionView dequeueReusableCellWithReuseIdentifier:@"cellIdentifier" forIndexPath:indexPath];
UIView *tmpView;
if([self.selectedEffects isEqualToString:@"Effects"]){
int index = indexPath.row;
NSLog(@"%i",index);
tmpView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 70, 90)];
[tmpView setBackgroundColor:[UIColor clearColor]];
UIImageView *imageViewWithEffect = [[UIImageView alloc] initWithFrame:CGRectMake(5, 0, 60, 60)];
imageViewWithEffect.layer.cornerRadius = 10.00;
imageViewWithEffect.clipsToBounds = YES;
UILabel *labelEffect = [[UILabel alloc] initWithFrame:CGRectMake(0, 65, 70, 20)];
[labelEffect setText:[[self.activeEffectsArray objectAtIndex:index] objectAtIndex:1]];
labelEffect.textAlignment = NSTextAlignmentCenter;
labelEffect.textColor = [UIColor whiteColor];
[labelEffect setFont:[UIFont boldSystemFontOfSize:8]];
UIActivityIndicatorView *activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
[activityIndicator setFrame:CGRectMake(0, 0, 60, 60)];
activityIndicator.alpha = 1.0;
[activityIndicator startAnimating];
UIButton *buttonSelect = [UIButton buttonWithType:UIButtonTypeCustom];
[buttonSelect setFrame:CGRectMake(0, 0, 60, 90)];
[buttonSelect setTag:index];
[buttonSelect addTarget:self action:@selector(applyEffects:) forControlEvents:UIControlEventTouchUpInside];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
UIImage *imageWithEffect = [self editImage:[[self.activeEffectsArray objectAtIndex:indexPath.row] objectAtIndex:0] ImageToEdit:self.thumbnailImage];
dispatch_async(dispatch_get_main_queue(), ^{
[imageViewWithEffect setImage:imageWithEffect];
[activityIndicator removeFromSuperview];
});
});
[tmpView addSubview:imageViewWithEffect];
[tmpView addSubview:labelEffect];
[tmpView addSubview:activityIndicator];
[tmpView addSubview:buttonSelect];
}
[cell addSubview:tmpView];
return cell;
}
You are adding subviews to the cell every time. This is incorrect because the cells may have been reused. Check if the subviews have already been created, and modify them if they're already there. You can do this by subclassing UICollectionViewCell, or using
viewWithTag:
(the former is preferable). There are hundreds of examples of this around so I won't rehash here.You also are referencing the same views in your dispatch block. This is also incorrect, because the cell may have been reused by the time the block is called. Instead, use the
indexPath
to get the cell again, and modify it that way.Finally, you may want to consider rounding the image corners on a background thread instead of using
layer.cornerRadius
- this approach will cause the image to be blended, which can cause choppy scrolling animations when you display lots of images at once.