iosuiviewuiimagecore-graphicsloadnibnamed

Take a snapshot of view without adding it to the screen


I'm trying to load a view from a nib, configure it, and take a snapshot of it, without adding it to the screen:

+ (void)composeFromNibWithImage:(UIImage*)catImage completion:(CompletionBlock)completion {

    NSArray *nibContents = [[NSBundle mainBundle] loadNibNamed:@"CatNib" owner:nil options:nil];
    CatView *catView = [nibContents firstObject];

    //here, catView is the correct size from the nib, but is blank if inspected with the debugger

    catView.catImageView.image = catImage;
    catView.furButton.selected = YES;    
    UIImage *composite = [UIImage snapshot:catView];
    completion(composite);
}

where snapshot is the typical:

+ (UIImage *)snapshot:(UIView *)view
{
    UIGraphicsBeginImageContextWithOptions(view.bounds.size, NO, 0.0);
    [view drawViewHierarchyInRect:view.bounds afterScreenUpdates:YES];
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return image;
}

However, both catView and composite are sized correctly but blank as I step through the code. How can I create a UIImage from a view that is loaded from a nib, without adding the view to the screen?


Solution

  • This feels a bit hacky, but I tried it and it does get the job done. If you load the view from your nib behind the main view, you can take a screenshot of just that layer. So long as it's not a memory intensive view, the user would never know that view was added to the super view.

    UIGraphicsBeginImageContext(CGSizeMake(catView.frame.size.width, catView.frame.size.height));
    CGContextRef context = UIGraphicsGetCurrentContext();
    [catView.layer renderInContext:context];
    UIImage *screenShot = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    

    So run this code after you load your nib behind your main view. Once it's loaded you can remove it with `[catView removeFromSuperiew]'