5

I have an application that's laid out using an UITableView. The interface takes up more than just the screen, so there's some area that can be scrolled to. I would like some screenshots of the entire view (including the non-visible area) to use for documentation and soliciting feedback from my customer.

Is there programmatic way to get an image of the entire view? I don't think there would be a way on the device to do this, but maybe there is.

Beardo
  • 1,542
  • 1
  • 14
  • 27

5 Answers5

6

Just pasting some code I used in my app. It draws a view to an image (potentially scaling). Maybe you could programmaticaly scroll the table and stitch the images together in the end or something similar:

+ (UIImage *)captureView: (UIView *)view inSize: (CGSize)size
{
    UIGraphicsBeginImageContext(size);
    CGSize viewSize = view.frame.size;
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextScaleCTM( context, size.width/viewSize.width, size.height/viewSize.height);

    [view.layer renderInContext: UIGraphicsGetCurrentContext()];

    UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return viewImage;
}

Hope it helps

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
Plamen Dragozov
  • 314
  • 2
  • 2
  • 2
    Yup, works like a champ if instead of making it scale, you simply use the size of the view, and when creating the UITableView, you make it tall enough for all logical cells in the view and standard width. – Beardo Feb 25 '10 at 03:58
4

You can actually scroll the tableview. The following code works perfect in my application. But it may take a white for making the screenshot. You may refer to this to see if anyone improved.

//viewController is your UITableViewController
UIGraphicsBeginImageContext(viewController.tableView.contentSize);
[viewController.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:NO];
[viewController.tableView.layer renderInContext:UIGraphicsGetCurrentContext()];

int rows = [viewController.tableView numberOfRowsInSection:0];
int numberofRowsInView = 7;
for (int i =0; i < rows/numberofRowsInView; i++) {
    [viewController.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:(i+1)*numberofRowsInView inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:NO];
    [viewController.tableView.layer renderInContext:UIGraphicsGetCurrentContext()];

}
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
Community
  • 1
  • 1
Zitao Xiong
  • 956
  • 1
  • 10
  • 18
1

Take a screenshot of the whole table view and not just visible cells. This approach doesn't require scrolling the table view and taking many screenshots and putting them together.

Works well with table view footer and header.

CGRect frame = _tableView.frame;
frame.size.height = _tableView.contentSize.height;//the most important line
_tableView.frame = frame;

UIGraphicsBeginImageContext(_tableView.bounds.size);
[_tableView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

NSData * data = UIImagePNGRepresentation(image);
Alexey
  • 7,127
  • 9
  • 57
  • 94
  • Perfect approach. This changes the height of the tableView's frame before taking the screenshot, so you don't have to bother with scrolling. Note you'll have to fiddle with the frame's height if you have a navigation bar visible. – Jeff Dec 05 '14 at 06:58
  • One edit: after UIGraphicsEndImageContext();, you should restore the tableView frame to what it originally was, or scrolling will be messed up. – Jeff Dec 05 '14 at 07:20
1

With a table view on the iphone, there is no "extra" area to scroll to. The table view is as big as the screen, and as new cells are scrolled into view, they're created on demand, while old cells that are scrolled off screen are deallocated.

Jasarien
  • 58,279
  • 31
  • 157
  • 188
  • Duly noted, however that doesn't really solve my problem of getting a screenshot of the entire interface (without multiple shots and then splicing them together). – Beardo Feb 24 '10 at 18:13
  • 1
    He's saying you do get the a screenshot of the entire interface. The parts of the table off screen are just logical. They have no visual manifestation at all. A table is not like a scrollview which just shows you part of a larger view. With a table, what you see is what exist. Every time you scroll the table, it rebuilds itself. Until you scroll to a position off screen, that position does not exist visually. – TechZen Feb 24 '10 at 18:16
  • @TechZen Yes, I understand that it builds it on the fly, what I want is a screenshot of the entire interface as if all logical cells were drawn (with as much space as that takes). – Beardo Feb 24 '10 at 18:22
  • @Bearddo so, to clarify, what you want is a picture of a really stretched out iPhone? – cobbal Feb 24 '10 at 18:29
  • Effectively, yes. Like say you wanted a picture of all your contacts in the Contacts app, not just the visible. Since I have the source to my app, I should be able to do this. Maybe just build a UITableView and lie to it about the size, and then render it with a different graphics context? – Beardo Feb 24 '10 at 18:33
  • @Bearddo Yep, you can add together the height of all the rows (using the UITableViewDelegate methods that you have already defined) and set that as the size for the table view itself. Then the problem turns into the more generic, and pretty interesting, one of capturing the whole interface, including views that are off-screen. – Felixyz Feb 24 '10 at 20:12
  • @Bearddo - I think you're banging you head against the wall trying to programmatically capture something that the user will never, ever see. I do not believe the non-visible rows will ever be drawn into the context. I believe the table will always truncate its drawing at the screen edge. It might be an interesting drill type problem but I wouldn't waste any production time on it. – TechZen Feb 24 '10 at 22:45
  • Although, it occurs to me that if you had a certain undisclosed SDK that ran on a wink, wink, nudge, nudge larger screen that was nevertheless very much like the iPhone, then you could configure a table to draw larger than the iPhone screen and capture that. – TechZen Feb 24 '10 at 22:47
  • @TechZen You aren't limited to the size of the screen, I just made the UITableView large enough to show everything, and write it do a different context (the same size) as shown in the accepted answer. Despite the user never seeing it that way, my client wants to see the entire user interface in one image, not separate ones and this will save me tons of time by not having to slice and dice separate images. – Beardo Feb 25 '10 at 04:03
  • Hah! Well, that's good know, it might prove useful in the future. It's not so bad being wrong when you learn something neat. – TechZen Feb 25 '10 at 12:09
1

As Jasarien said, a UITableView has no off screen elements. It's just a stage illusion that creates the appearance of single long element.

If you want to create an image of long (i.e. offscreen) table, you should take screenshots of the table at different scroll positions and then Photoshop/GIMP/insert-graphics-app the screenshots into one long graphic.

Community
  • 1
  • 1
TechZen
  • 64,370
  • 15
  • 118
  • 145