Search code examples
iphoneobjective-cuitableviewcore-animation

Why are CALayers stacking ontop of each other as I scroll my UITableView?


I have a UITableViewCell with a UIImage that I'm drawing. As I scroll, I get a ton of sublayers getting added which makes performance really jerky. How can I make sure my CALayer only gets added once?

- (void) drawContentView:(CGRect)rect {
    CGContextRef context = UIGraphicsGetCurrentContext();
    [[UIColor whiteColor] set];
    CGContextFillRect(context, rect);

    NSString* caption = [NSString stringWithFormat:@"%@",[info objectForKey:@"caption"]];
    NSString* text = [info stringForKey:@"text"];

    CGFloat widthr = self.frame.size.width - 70;

    [[UIColor grayColor] set];
    [text drawInRect:CGRectMake(63.0, 25.0, widthr, 20.0) withFont:system14 lineBreakMode:UILineBreakModeTailTruncation];

    if (self.image) {
        UIImage *imageToDisplay;
        imageToDisplay = self.image;
        imageToDisplay = [self imageWithImage:imageToDisplay scaledToSize:CGSizeMake(imageToDisplay.size.width / 1.5, imageToDisplay.size.height / 1.5)];
        CGFloat width;
        CGFloat height;
        CGRect r;
        if (imageToDisplay.size.width < 310 && imageToDisplay.size.height > 290) {
            imageToDisplay = [self imageByCropping:imageToDisplay toRect:CGRectMake(0, 20, imageToDisplay.size.width, 270)];

        }
        else if (imageToDisplay.size.width > 310 && imageToDisplay.size.height < 20) {
            imageToDisplay = [self imageByCropping:imageToDisplay toRect:CGRectMake(30, 0, 290, imageToDisplay.size.height)];
        }
        else {
            if (![caption isEqualToString:@""]) {
                imageToDisplay = [self imageByCropping:imageToDisplay toRect:CGRectMake(30, 0, 290, 230)];
            }
            else {
            imageToDisplay = [self imageByCropping:imageToDisplay toRect:CGRectMake(30, 0, 290, 270)];
            }
        }

        width = imageToDisplay.size.width;
        height = imageToDisplay.size.height;
        r = CGRectMake(5.0, 5.0, width, height);

        //[imageToDisplay drawInRect:r];

        CALayer *sublayer = [CALayer layer];
        sublayer.contents = (id)imageToDisplay.CGImage;
        sublayer.shadowOffset = CGSizeMake(0, 3);
        sublayer.shadowRadius = 5.0;
        sublayer.shadowColor = [UIColor blackColor].CGColor;
        sublayer.shadowOpacity = 0.8;
        sublayer.frame = CGRectMake(5.0, 5.0, imageToDisplay.size.width, imageToDisplay.size.height);
        [self.layer addSublayer:sublayer];

        //Experimental shadow stuff with images
        /*CALayer *layer = [CALayer layer];
        layer = [CALayer layer];
        layer.bounds = CGRectMake(5.0, 5.0, imageToDisplay.size.width, imageToDisplay.size.height);
        layer.position = CGPointMake(150, 140);
        layer.contents = (id)imageToDisplay.CGImage;    

        layer.shadowOffset = CGSizeMake(0, 2);
        layer.shadowOpacity = 0.70;

        [self.layer addSublayer:layer];

        [self bezierPathWithCurvedShadowForRect:layer.bounds];*/

        [[UIColor blackColor] set];
        [caption drawInRect:CGRectMake(10.0, height + 20 , widthr, 20.0) withFont:system14 lineBreakMode:UILineBreakModeWordWrap alignment:UITextAlignmentCenter];
    }
}

Solution

  • drawContentView: is not the right method from which to call addSublayer:. You should add that layer at the point when you construct your object with an image, or when you set an image on an existing object. Alternatively, you can draw the image yourself in the drawContentView:, but it is probably not going to be as fast.