Preventing UICollectionView From Redrawing

2019-08-08 06:12发布

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

1条回答
一夜七次
2楼-- · 2019-08-08 06:32

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.

查看更多
登录 后发表回答