I have simple UITableView
with some data. The table\'s height is greater than the screen size. Now I need to catch screenshot of this table (a whole table). I k
I have same requirement to send image of tableview to admin via email, Hope this will help you. Function implemented in swift 4
func screenshot() -> UIImage{
var image = UIImage()
UIGraphicsBeginImageContextWithOptions(self.tblDetails.contentSize, false, UIScreen.main.scale)
// save initial values
let savedContentOffset = self.tblDetails.contentOffset
let savedFrame = self.tblDetails.frame
let savedBackgroundColor = self.tblDetails.backgroundColor
// reset offset to top left point
self.tblDetails.contentOffset = CGPoint(x: 0, y: 0)
// set frame to content size
self.tblDetails.frame = CGRect(x: 0, y: 0, width: self.tblDetails.contentSize.width, height: self.tblDetails.contentSize.height)
// remove background
self.tblDetails.backgroundColor = UIColor.clear
// make temp view with scroll view content size
// a workaround for issue when image on ipad was drawn incorrectly
let tempView = UIView(frame: CGRect(x: 0, y: 0, width: self.tblDetails.contentSize.width, height: self.tblDetails.contentSize.height))
// save superview
let tempSuperView = self.tblDetails.superview
// remove scrollView from old superview
self.tblDetails.removeFromSuperview()
// and add to tempView
tempView.addSubview(self.tblDetails)
// render view
// drawViewHierarchyInRect not working correctly
tempView.layer.render(in: UIGraphicsGetCurrentContext()!)
// and get image
image = UIGraphicsGetImageFromCurrentImageContext()!
// and return everything back
tempView.subviews[0].removeFromSuperview()
tempSuperView?.addSubview(self.tblDetails)
// restore saved settings
self.tblDetails.contentOffset = savedContentOffset
self.tblDetails.frame = savedFrame
self.tblDetails.backgroundColor = savedBackgroundColor
UIGraphicsEndImageContext()
return image
}
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)!
print("row:\(indexPath.row), frame:\(cell.frame) height:\(cell.frame.height)")
cell.contentView.drawViewHierarchyInRect(cell.frame, afterScreenUpdates: true)
}
}
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
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)
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
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.
My solution for Swift 4 !
import Foundation
import UIKit
extension UITableView {
func asFullImage() -> UIImage? {
guard self.numberOfSections > 0, self.numberOfRows(inSection: 0) > 0 else {
return nil
}
self.scrollToRow(at: IndexPath(row: 0, section: 0), at: .top, animated: false)
var height: CGFloat = 0.0
for section in 0..<self.numberOfSections {
var cellHeight: CGFloat = 0.0
for row in 0..<self.numberOfRows(inSection: section) {
let indexPath = IndexPath(row: row, section: section)
guard let cell = self.cellForRow(at: indexPath) else { continue }
cellHeight = cell.frame.size.height
}
height += cellHeight * CGFloat(self.numberOfRows(inSection: section))
}
UIGraphicsBeginImageContextWithOptions(CGSize(width: self.contentSize.width, height: height), false, UIScreen.main.scale)
for section in 0..<self.numberOfSections {
for row in 0..<self.numberOfRows(inSection: section) {
let indexPath = IndexPath(row: row, section: section)
guard let cell = self.cellForRow(at: indexPath) else { continue }
cell.contentView.drawHierarchy(in: cell.frame, afterScreenUpdates: true)
if row < self.numberOfRows(inSection: section) - 1 {
self.scrollToRow(at: IndexPath(row: row+1, section: section), at: .bottom, animated: false)
}
}
}
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image!
}
}