iOS开发 - tableView长截图iOS15适配(Swift版)

2021年苹果秋季发布会之后,iOS15的推出,给开发带来了不少的适配问题。(可恶!)

没办法,那是爸爸。我改咯~😮💨

先贴上在iOS14及以下版本,正常的长截图完整代码.

  1. 建立一个UITableView的扩展extension
extension UITableView {
    
    /// 获取最大高度
    /// - Parameters:
    ///   - maxRowCount: 最大row的count
    ///   - maxSectionCount: 最大section的count,为0表示所有
    public func getMaxHeight(with maxRowCount: Int, maxSectionCount: Int = 0) -> CGFloat {
        var sectionCount = maxSectionCount
        if maxSectionCount >= numberOfSections || maxSectionCount <= 0 {
            sectionCount = numberOfSections
        }
        var maxHeight: CGFloat = tableHeaderView?.frame.size.height ?? 0;
        for sectionIndex in 0..<sectionCount {
            var rowCount = numberOfRows(inSection: sectionIndex)
            if (rowCount > maxRowCount) {
                rowCount = maxRowCount;
            }
            
            maxHeight += delegate?.tableView?(self, heightForHeaderInSection: sectionCount) ?? 0
            for rowIndex in 0..<rowCount {
                maxHeight += delegate?.tableView?(self, heightForRowAt: IndexPath(row: rowIndex, section: sectionIndex)) ?? 0
                
            }
        }
        return maxHeight;
    }
    
    /// 获取指定高度的tableView image
    /// - Parameter maxHeight: 最大高度
    public func generateTableViewImage(with maxHeight: CGFloat) -> UIImage? {
        var viewImage: UIImage?
        
        let savedContentOffset = contentOffset
        let savedFrame = frame
        
        let imageHeight = maxHeight > 0 ? maxHeight :contentSize.height
        var screensInTable = 0
        
        if (frame.size.height != 0) {
            screensInTable = Int(ceil(imageHeight / frame.size.height))
        }
        
        let sectionNum = numberOfSections
        
//        autoreleasepool {
            let imageSize = CGSize(width: frame.size.width, height: maxHeight)
            UIGraphicsBeginImageContextWithOptions(imageSize, false, UIScreen.main.scale)
            
            frame = CGRect(x: 0, y: 0, width: contentSize.width, height: imageHeight)
            
            for i in 0..<screensInTable {
                let contentOffset = CGPoint(x: CGFloat(0), y: CGFloat(i) * frame.size.height)
                setContentOffset(contentOffset, animated: false)
                
                // 隐藏应该移出屏幕的sectionHeader
                if (style == .plain) {
                    for i in 0..<sectionNum {
                        let headerRect = rect(forSection: i)
                        if (headerRect.origin.y < contentOffset.y) {
                            setupHeaderView(with: i, true)
                        }
                    }
                }
                if let context = UIGraphicsGetCurrentContext() {
                    layer.render(in: context)
                }
            }
//        }
       
        viewImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        
        if (style == .plain) {
            for i in 0..<sectionNum {
                setupHeaderView(with: i, false)
            }
        }
        
        frame = savedFrame
        setContentOffset(savedContentOffset, animated: false)
        return viewImage
    }
    
    /// 设置HeaderView的显示隐藏
    /// - Parameters:
    ///   - section: header所在的section
    ///   - isHidden: 是否隐藏
    private func setupHeaderView(with section: Int, _ isHidden: Bool) {
        
        var headerView1 = headerView(forSection: section)
        
        if nil == headerView {
            headerView1 = delegate?.tableView?(self, viewForHeaderInSection: section) as? UITableViewHeaderFooterView
        }
        headerView1?.isHidden = isHidden
    }
}
  1. 使用代码. 这里的10,是指最大row的数量。详细代码在extension,就不叙述了。
guard let image = longShareImageTableView.generateTableViewImage(with: longShareImageTableView.getMaxHeight(with: 10)) else {

                return
            }

            shareImage = image

到了iOS15,截图就会缺失了一部分,举个栗子🌰

WX20211103-140003@2x.png

很是迷茫,网上好像暂时没有相应的资料和解决办法。后来在https://jishuin.proginn.com/p/763bfbd564b3这篇文章中,找到了灵感之处。

if #available(iOS 13, *) {
       //iOS 13 系统截屏需要改变tableview 的bounds
       scrollView.layer.bounds = CGRect(x: oldBounds.origin.x, y: oldBounds.origin.y, width: contentSize.width, height: contentSize.height)
   }
   //偏移量归零
   scrollView.contentOffset = CGPoint.zero
   //frame变为contentSize
   scrollView.frame = CGRect(x: 0, y: 0, width: scrollView.contentSize.width, height: scrollView.contentSize.height)

但实测之后发现,把这段结合到自己的截图方法中后,反而会令iOS13版本的截图缺失,iOS15倒是正常了。。。😮

最后只能把代码变成iOS15之后使用了,最终的代码如下

/// 获取指定高度的tableView image
    /// - Parameter maxHeight: 最大高度
    public func generateTableViewImage(with maxHeight: CGFloat) -> UIImage? {
        var viewImage: UIImage?
        
        let savedContentOffset = contentOffset
        let savedFrame = frame
        
        let imageHeight = maxHeight > 0 ? maxHeight :contentSize.height
        var screensInTable = 0
        
        if (frame.size.height != 0) {
            screensInTable = Int(ceil(imageHeight / frame.size.height))
        }
        
        let sectionNum = numberOfSections
        
//        autoreleasepool {
            let imageSize = CGSize(width: frame.size.width, height: maxHeight)
            UIGraphicsBeginImageContextWithOptions(imageSize, false, UIScreen.main.scale)
            
            frame = CGRect(x: 0, y: 0, width: contentSize.width, height: imageHeight)
            
            let oldBounds = layer.bounds
            
        
            if #available(iOS 15, *) {
                //iOS 15 系统截屏需要改变tableview 的bounds
                layer.bounds = CGRect(x: oldBounds.origin.x,
                                                 y: oldBounds.origin.y,
                                                 width: contentSize.width,
                                                 height: contentSize.height)
                
                //偏移量归零
                contentOffset = CGPoint.zero
                //frame变为contentSize
                frame = CGRect(x: 0, y: 0, width: contentSize.width, height: contentSize.height)
            }
            
            
            for i in 0..<screensInTable {
                let contentOffset = CGPoint(x: CGFloat(0), y: CGFloat(i) * frame.size.height)
                setContentOffset(contentOffset, animated: false)
                
                // 隐藏应该移出屏幕的sectionHeader
                if (style == .plain) {
                    for i in 0..<sectionNum {
                        let headerRect = rect(forSection: i)
                        if (headerRect.origin.y < contentOffset.y) {
                            setupHeaderView(with: i, true)
                        }
                    }
                }
                if let context = UIGraphicsGetCurrentContext() {
                    layer.render(in: context)
                }
            }
//        }
        
        if #available(iOS 15, *) {
            layer.bounds = oldBounds
        }
        
        viewImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        
        if (style == .plain) {
            for i in 0..<sectionNum {
                setupHeaderView(with: i, false)
            }
        }
        
        frame = savedFrame
        setContentOffset(savedContentOffset, animated: false)
        return viewImage
    }
WX20211103-135835@2x.png

打完!收工!
攰死个人了😂

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 本文作为自己准备适配iOS15所用,在开始适配之前,先去学习各位同学的文章,记录在此备用。 1、导航栏UINavi...
    iOS_zy阅读 14,575评论 5 61
  • 设备升级到iOS15之后,电池条,导航条和底部tabBar的背景色,都成为了透明色,这给了APP设计极大的灵活性,...
    晒太阳的仙人掌是个程序媛阅读 2,399评论 0 6
  • UINavigationBar 用新 xcode13 编译工程后,导航栏的问题比较明显,调试之后发现是 UINav...
    林希品阅读 3,740评论 0 10
  • ios18 1、collectioncell崩溃:collectionView返回同一cell之前不允许deque...
    冷武橘阅读 2,451评论 1 9
  • 本文主要分享一下 iOS15 上适配方案,仅做开发记录使用,开发过程中通过使用陆续增加。 iOS15 的适配,很重...
    smile丽语阅读 5,344评论 11 24