【问题标题】:How to render a whole UITableView as an UIImage in iOS?如何在 iOS 中将整个 UITableView 渲染为 UIImage?
【发布时间】:2015-08-20 09:41:02
【问题描述】:

我有简单的UITableView 和一些数据。表格的高度大于屏幕尺寸。现在我需要捕捉这张桌子(整张桌子)的截图。我知道内容后的单元格出队,但也许有一种方法可以捕捉到这一点。不是吗?

【问题讨论】:

标签: ios swift uitableview


【解决方案1】:

试试这个:

 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 numberofRowsThatShowOnScreen = 4
        var scrollCount = row / numberofRowthatShowinscreen
        
        for var i = 0; i < scrollCount; i++ {
            tblview.scrollToRowAtIndexPath(NSIndexPath(forRow: (i+1) * numberofRowsThatShowOnScreen, inSection: 0), atScrollPosition: UITableViewScrollPosition.Top, animated: false)
            tblview.layer.renderInContext(UIGraphicsGetCurrentContext())
        }
        
        let image:UIImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext();
        return image;
}


        
 

然后像这样调用方法。

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

【讨论】:

【解决方案2】:

只是 UITableView 的单元格到 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()

【讨论】:

    【解决方案3】:

    我的 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!
        }
    }
    
    

    【讨论】:

    • 那行得通。但图片显示不正确。
    【解决方案4】:

    Young Hoo Kim 的 Swift 3 版本的答案对我有用:

    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
    }
    

    需要注意的是,如果你的 UITableView 特别长,你可能无法使用上面的函数来捕捉它,因为它可能需要太大的图像。

    【讨论】:

      【解决方案5】:

      Parth Bhadaja 回答的 Swift 4 版本:

      func generateImage(tableView:UITableView) -> UIImage {
          UIGraphicsBeginImageContext(tableView.contentSize);
          tableView.scrollToRow(at: NSIndexPath(row: 0, section: 0) as IndexPath, at: UITableViewScrollPosition.top, animated: false)
          tableView.layer.render(in: UIGraphicsGetCurrentContext()!)
          let row = tableView.numberOfRows(inSection: 0)
          let numberofRowthatShowinscreen = 4
          let scrollCount = row / numberofRowthatShowinscreen
      
          for i in 0..<scrollCount {
              tableView.scrollToRow(at: NSIndexPath(row: (i+1)*numberofRowthatShowinscreen, section: 0) as IndexPath, at: UITableViewScrollPosition.top, animated: false)
              tableView.layer.render(in: UIGraphicsGetCurrentContext()!)
          }
      
          let image:UIImage = UIGraphicsGetImageFromCurrentImageContext()!
          UIGraphicsEndImageContext();
          return image;
      }
      

      需要注意的是,这个函数确实返回了整个 tableView 的图像,甚至包括尚未加载到屏幕上的单元格。

      【讨论】:

      • 在 iOS 14 和 Swift 5 中无法使用。屏幕外部分仅在颜色中显示。
      【解决方案6】:

      要截取 UIView 的屏幕截图,您可以使用以下命令:

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

      这适用于任何可见的内容,并且可能适用于任何已加载但屏幕外的视图。
      在 UITableView 中,仅加载可见单元格以及表格两端的 1 个屏幕外单元格。其他的实际上并不存在......但是。所以你不能“捕获”它们。

      【讨论】:

        【解决方案7】:

        您可以使用 tableView.contentSize 的大小创建图形上下文。之后,您必须运行循环抛出所有 indexPaths 并绘制每个单元格。您可以拥有一个单元格,该单元格将被重复用于绘制屏幕外的单元格 - 只需使用所需数据更改其内容并绘制它。

        【讨论】:

          【解决方案8】:

          使用 swift 2.2 获取 uitableview 的快照:

          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();
          }
          

          【讨论】:

            【解决方案9】:

            转移了 Parth Bhadaja 对 Swift 3 的回答,并作为计算属性的扩展:

            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;
                }
            }
            

            用法:

            let image = tableView.capturedImage
            

            【讨论】:

              【解决方案10】:

              我有同样的要求通过电子邮件将 tableview 的图像发送给管理员,希望这会对你有所帮助。 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
              }
              

              【讨论】:

              • 使用此代码为我正确地从 tableview 呈现图像。但是,表格视图变为空白/白色。任何想法为什么?
              【解决方案11】:

              render方法添加到UITableViewcategory

              - (UIImage *)render {
              
                  //save the origin info 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 info
                  self.contentOffset = originContentOffset;
              
                  return image;
              }
              

              【讨论】:

                【解决方案12】:

                只是一个稍有改进的替代解决方案:

                • 它根据内容偏移量而不是行数滚动内容。
                • 如果可用,它会考虑页眉和页脚视图(tableHeaderViewtableFooterView)。如果您从第一行开始捕获,在某些情况下将无法完全获取内容。
                • contentOffset 在进程开始之前存储,以便在滚动+捕获完成时再次设置。
                extension UITableView {
                    
                    var tableViewAsImage: UIImage? {
                        let offset = contentOffset
                        UIGraphicsBeginImageContext(contentSize)
                
                        guard let currentContext = UIGraphicsGetCurrentContext() else {
                            return nil
                        }
                        setContentOffset(.zero, animated: false)
                        layer.render(in: currentContext)
                        
                        let height = bounds.height
                        let totalHeight = contentSize.height
                        let scrollCount = Int((height / totalHeight).rounded())
                        
                        for i in 0...scrollCount {
                            let y: CGFloat = CGFloat(i) * height
                            setContentOffset(.init(x: 0, y: y), animated: false)
                            layer.render(in: currentContext)
                        }
                        let image = UIGraphicsGetImageFromCurrentImageContext()
                        UIGraphicsEndImageContext()
                        setContentOffset(offset, animated: false)
                        return image
                    }
                    
                }
                

                【讨论】:

                  【解决方案13】:

                  UItableView 通过不要一次创建所有单元格,但您可以强制 tableView 加载所有(不推荐)解决方法只是设置tableView @ 的高度987654323@ 这将使它加载tableView 所有行。 您可以将视图转换为如下所示的图像

                  + (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;
                  }
                  

                  【讨论】:

                    【解决方案14】:
                    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();
                    

                    animation设置为NO很重要,不要阻塞UI线程

                    【讨论】:

                      猜你喜欢
                      • 2019-05-16
                      • 1970-01-01
                      • 2013-07-20
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      相关资源
                      最近更新 更多