4

I used the code below for years to be able to capture a screenshot of an UITableView (including hidden rows) and save it to the user's phone gallery or share it.

Since they updated to iOS 13 it doesn't work anymore, it captures only the visible part of the table leaving it blank on the bottom part.

-(UIImage *)imageFromCurrentTable
{
    CGRect frame = self.tableView.frame;
    frame.size.height = self.tableView.contentSize.height;
    self.tableView.frame = frame;
        UIGraphicsBeginImageContext(self.tableView.bounds.size);
    [self.tableView.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();    
    NSData * data = UIImagePNGRepresentation(image);
    return [UIImage imageWithData:data];
}

What changed in iOS 13? How this code can be updated? (the code is Obj-C but I will accept also swift answers!)

lorenzop
  • 580
  • 1
  • 6
  • 24
  • I’m a little surprised that this worked at all (that `renderInContext` would trigger all of the necessary `UITableViewDataSource` calls seems unlikely). I might try temporarily adjusting the `frame` (resetting it when you’re done) of the table view to encompass the whole `contentSize` and then call [`drawviewhierarchyinrect:afterScreenUpdates:`](https://developer.apple.com/documentation/uikit/uiview/1622589-drawviewhierarchyinrect?language=objc). And even that will only work if the cells are fixed sized. – Rob Sep 25 '19 at 04:50
  • It worked really smooth until iOS 13. One of these things that you don't even ask why! Will try your solution – lorenzop Sep 25 '19 at 05:23
  • I used this solution and seems to work, but it is quite ugly https://stackoverflow.com/a/36028210/1187692 – lorenzop Sep 25 '19 at 06:35
  • Yeah, that answer, as ugly as it appears, is precisely the sort of thing that one should do. Cells are reused and you can’t just, for example, draw a tableview and expect the rows for cells off screen to be rendered correctly (because the cells for those have been reused for the cells that are currently visible). You really need to iterate through the cells and manually draw them. By the way, even this is an over simplification if, for example, the cells are of dynamic sizes because the `contentSize` is using the estimated row height for rows that haven’t been rendered yet. – Rob Sep 25 '19 at 22:04
  • One other caveat: If on retina device, this will render a low resolution, non-retina, sized image. Perhaps that’s OK, but just to warn you. Generally you’d use `UIGraphicsBeginImageContextWithOptions`, passing `0` for the scale, to capture the full resolution. It depends upon the intended purpose of the resulting image. – Rob Sep 25 '19 at 22:06

1 Answers1

0

I have faced this issue. Due to cell Reuse, UIGraphicsGetImageFromCurrentImageContext cannot produce full UITableView structure.

One Way [Not Efficient Way]:

  • In cellForRowAtIndexPath, we can able to get which UITableViewCell using. Store that cell in [Int: UITableViewCell].
  • Get screenshot from UITableViewCell.contentView.
  • Add that screenshot's image as subview to UIView one by one.
  • Now, UIView having UITableView's contentView as Images.
  • Get screenshot from UIView.
McDonal_11
  • 3,935
  • 6
  • 24
  • 55