How to render a whole UITableView as an UIImage in iOS?

10 Solutions Collect From Internet About “How to render a whole UITableView as an UIImage in iOS?”

Try this:

 func generateImage(tblview:UITableView) ->UIImage{
        UIGraphicsBeginImageContext(tblview.contentSize);
        tblview.scrollToRowAtIndexPath(NSIndexPath(forRow: 0, inSection: 0), atScrollPosition: UITableViewScrollPosition.Top, animated: false)
        tblview.layer.renderInContext(UIGraphicsGetCurrentContext())
        let row = tblview.numberOfRowsInSection(0)
        let numberofRowthatShowinscreen = 4
        var scrollCount = row / numberofRowthatShowinscreen

        for var i=0;i < scrollCount ; i++ {
            tblview.scrollToRowAtIndexPath(NSIndexPath(forRow: (i+1)*numberofRowthatShowinscreen, inSection: 0), atScrollPosition: UITableViewScrollPosition.Top, animated: false)
            tblview.layer.renderInContext(UIGraphicsGetCurrentContext())
        }

        let image:UIImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext();
        return image;
}

and after call method like this.

 var imageView = UIImageView()
     imageView.image =generateImage(tableView)

Just UITableView’s cells to UIImage

UIGraphicsBeginImageContextWithOptions(CGSizeMake(tableView.contentSize.width, tableView.contentSize.height+64+40), true, 0)

for section in 0...tableView.numberOfSections-1 {
    for row in 0...tableView.numberOfRowsInSection(section)-1 {
        let indexPath = NSIndexPath.init(forRow: row, inSection: section)
        let cell = tableView.cellForRowAtIndexPath(indexPath)!
        let height = cell.frame.height

        print("row:\(indexPath.row), frame:\(cell.frame) height:\(height)")

        cell.contentView.drawViewHierarchyInRect(cell.frame, afterScreenUpdates: true)
    }
}
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()

To take a screenshot of an UIView you can use the following:

UIGraphicsBeginImageContext(tableview.frame.size)
tableview.layer.renderInContext(UIGraphicsGetCurrentContext())
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext() 

This will work for whatever is visible, and may work for any already loaded but off-screen views.
In an UITableView, only the visible cells plus 1 off-screen cell at each end of the table are loaded. The other ones do not actually exist… yet. So you can’t “capture” them.

You can create graphics context with the size of tableView.contentSize. After that you have to run loop threw all indexPaths and draw each cell. You can have one cell which will be reused for drawing cells which are out of screen – just change content of that with required data and draw it.

For snapshot in of uitableview with swift 2.2:

func printScreen(){
    UIGraphicsBeginImageContextWithOptions(Table_LigaParcial.contentSize, false, UIScreen.mainScreen().scale)
    Table_LigaParcial.scrollToRowAtIndexPath(NSIndexPath(forRow: 0, inSection: 0), atScrollPosition: UITableViewScrollPosition.Top, animated: false)
    Table_LigaParcial.layer.renderInContext(UIGraphicsGetCurrentContext()!)
    let row = Table_LigaParcial.numberOfRowsInSection(0)
    let numberofRowthatShowinscreen = 4
    var scrollCount = row / numberofRowthatShowinscreen

    for var i=0;i < scrollCount ; i+=1 {
        Table_LigaParcial.scrollToRowAtIndexPath(NSIndexPath(forRow: (i)*numberofRowthatShowinscreen, inSection: 0), atScrollPosition: UITableViewScrollPosition.Top, animated: false)
        Table_LigaParcial.layer.renderInContext(UIGraphicsGetCurrentContext()!)
    }

    let image:UIImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext();
}

Tranfered Parth Bhadaja’s answer to Swift 3 and as extension with computed property:

extension UITableView {
    var capturedImage : UIImage {
        UIGraphicsBeginImageContext(contentSize);
        scrollToRow(at: NSIndexPath(row: 0, section: 0) as IndexPath, at:     UITableViewScrollPosition.top, animated: false)
        layer.render(in: UIGraphicsGetCurrentContext()!)
        let row = numberOfRows(inSection: 0)
        let numberofRowthatShowinscreen = 4
        let scrollCount = row / numberofRowthatShowinscreen

        for i in 0 ..< scrollCount  {
            scrollToRow(at: NSIndexPath(row: (i+1)*numberofRowthatShowinscreen, section: 0) as     IndexPath, at: UITableViewScrollPosition.top, animated: false)
            layer.render(in: UIGraphicsGetCurrentContext()!)
        }

        let image:UIImage = UIGraphicsGetImageFromCurrentImageContext()!
        UIGraphicsEndImageContext();
        return image;
    }
}

Usage:

let image = tableView.capturedImage

Swift 3 version of Young Hoo Kim’s answer works for me:

func generateTableViewImage(_ tableView: UITableView) -> UIImage? {
    UIGraphicsBeginImageContextWithOptions(tableView.contentSize, false, UIScreen.main.scale)

    for section in 0..<tableView.numberOfSections {
        for row in 0..<tableView.numberOfRows(inSection: section) {
            let indexPath = IndexPath(row: row, section: section)
            guard let cell = tableView.cellForRow(at: indexPath) else { continue }
            cell.contentView.drawHierarchy(in: cell.frame, afterScreenUpdates: true)
        }
    }
    let image = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return image
}

It should be noted that if your UITableView is particularly long you may not be able to capture it with the function above as it may require too large an image.

UItableView by don’t create all cells at a time, but you can force tableView to load all (which is not recommended) work around is just set the height of tableView ( numRows * heightOfRow) and this will make it load tableView all rows.
And you can convert view to image like below

+ (UIImage*)imageFromView:(UIView *)view{
       UIGraphicsBeginImageContextWithOptions(view.bounds.size, NO, [UIScreen mainScreen].scale);
    [view drawViewHierarchyInRect:CGRectMake(0, 0, view.bounds.size.width, view.bounds.size.height) afterScreenUpdates:YES];
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return image;
}

add render method to UITableView through category

- (UIImage *)render {

    //save the origin infos for later to restore
    CGPoint originContentOffset = self.contentOffset;

    //force jump to table view's top
    self.contentOffset = CGPointZero;

    UIGraphicsBeginImageContext(self.contentSize);

    CGContextRef *ctx = UIGraphicsGetCurrentContext();

    //render header 
    [self.tableHeaderView.layer renderInContext:ctx];

    //render sections
    NSInteger numberOfSections = [self numberOfSections];
    for (int section = 0; section < numberOfSections; section++) {
        NSInteger numberOfRows = [self numberOfRowsInSection:section];
        for (int row = 0; row < numberOfRows; row++) {
            NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:section];
            //check cell is visible
            if ([self cellForRowAtIndexPath:indexPath]) {
                [self scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionTop animated:false];
                [self.layer renderInContext:ctx];
            }
        }
    }

    //render footer
    [self.tableFooterView.layer renderInContext:ctx];

    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    //restore infos
    self.contentOffset = originContentOffset;

    return image;
}
UIGraphicsBeginImageContextWithOptions(CGSizeMake(self.tableView.contentSize.width, self.tableView.contentSize.height), YES, 0);

CGFloat originY = 0;

CGRect rectFirst =  CGRectMake(0, originY, self.tableView.bounds.size.width, self.view.bounds.size.height);

[self.tableView scrollRectToVisible:rectFirst animated:NO];

[self.tableView drawViewHierarchyInRect:rectFirst afterScreenUpdates:true];

while (originY < self.tableView.contentSize.height) {

   CGRect rectSecond =  CGRectMake(0, originY, self.tableView.bounds.size.width, self.view.bounds.size.height);

    [self.tableView scrollRectToVisible: rectSecond animated:NO];

    [self.tableView drawViewHierarchyInRect: rectSecond afterScreenUpdates:true];

    originY += self.view.bounds.size.height;

}

CGRect rectFinally =  CGRectMake(0, originY, self.tableView.bounds.size.width, self.tableView.contentSize.height - originY);

[self.tableView scrollRectToVisible:rectFinally animated:NO];

[self.tableView drawViewHierarchyInRect:rectFinally afterScreenUpdates:true];

UIImage * image = UIGraphicsGetImageFromCurrentImageContext();  

UIGraphicsEndImageContext();

It’s very important to set animated to NO, and don’t block the UI thread