获取UICollectionView

时间:2015-09-24 23:22:27

标签: swift uiimage uicollectionview

我正在处理的应用使用集合视图单元格向用户显示数据。我希望用户能够共享单元格中包含的数据,但通常会有太多单元格尝试重新调整大小并适合单个iPhone屏幕大小的窗口并获取屏幕截图。

所以我遇到的问题是尝试在屏幕上和屏幕外的集合视图中获取所有单元格的图像。我知道屏幕外的细胞实际上并不存在,但我对一种伪造图像和绘制数据的方式感兴趣(如果可能的话)迅速)。

简而言之,有没有办法以编程方式从集合视图及其包含的单元格创建图像,无论是在屏幕上还是在屏幕外使用Swift?

3 个答案:

答案 0 :(得分:3)

更新

如果记忆不是问题:

mutating func screenshot(scale: CGFloat) -> UIImage {
    let currentSize = frame.size
    let currentOffset = contentOffset // temp store current offset

    frame.size = contentSize
    setContentOffset(CGPointZero, animated: false)        

    // it might need a delay here to allow loading data.

    let rect = CGRect(x: 0, y: 0, width: self.bounds.size.width, height: self.bounds.size.height)
    UIGraphicsBeginImageContextWithOptions(rect.size, false, UIScreen.mainScreen().scale)
    self.drawViewHierarchyInRect(rect, afterScreenUpdates: true)
    let image = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    frame.size = currentSize
    setContentOffset(currentOffset, animated: false)

    return resizeUIImage(image, scale: scale)        
}

这对我有用:

github link - >包含最新代码

getScreenshotRects创建要滚动的偏移量和要捕获的帧。 (命名并不完美)

takeScreenshotAtPoint滚动到该点,设置延迟以允许重绘,截取屏幕截图并通过完成处理程序返回。

stitchImages创建一个与内容大小相同的矩形,并在其中绘制所有图像。

makeScreenshotsdidSet的嵌套数组和计数器上使用UIImage来创建所有图像,同时等待完成。完成后,它会激活它自己的完成处理程序。

基本部分:

  • 滚动收集视图 - >的工作原理
  • 带有延迟的截图以进行重绘 - >的工作原理
  • 裁剪重叠的图像 - > 显然不需要
  • 缝合所有图像 - >的工作原理
  • 基础数学 - >的工作原理
  • 可能会在发生这一切时冻结屏幕或隐藏(这不在我的回答中)

代码:

protocol ScrollViewImager {

    var bounds : CGRect { get }

    var contentSize : CGSize { get }

    var contentOffset : CGPoint { get }

    func setContentOffset(contentOffset: CGPoint, animated: Bool)

    func drawViewHierarchyInRect(rect: CGRect, afterScreenUpdates: Bool) -> Bool
}

extension ScrollViewImager {

    func screenshot(completion: (screenshot: UIImage) -> Void) {

        let pointsAndFrames = getScreenshotRects()
        let points = pointsAndFrames.points
        let frames = pointsAndFrames.frames

        makeScreenshots(points, frames: frames) { (screenshots) -> Void in
            let stitched = self.stitchImages(images: screenshots, finalSize: self.contentSize)
            completion(screenshot: stitched!)
        }

    }

    private func makeScreenshots(points:[[CGPoint]], frames : [[CGRect]],completion: (screenshots: [[UIImage]]) -> Void) {

        var counter : Int = 0

        var images : [[UIImage]] = [] {
            didSet {
                if counter < points.count {
                    makeScreenshotRow(points[counter], frames : frames[counter]) { (screenshot) -> Void in
                        counter += 1
                        images.append(screenshot)
                    }
                } else {
                    completion(screenshots: images)
                }
            }
        }

        makeScreenshotRow(points[counter], frames : frames[counter]) { (screenshot) -> Void in
            counter += 1
            images.append(screenshot)
        }

    }

    private func makeScreenshotRow(points:[CGPoint], frames : [CGRect],completion: (screenshots: [UIImage]) -> Void) {

        var counter : Int = 0

        var images : [UIImage] = [] {
            didSet {
                if counter < points.count {
                    takeScreenshotAtPoint(point: points[counter]) { (screenshot) -> Void in
                        counter += 1
                        images.append(screenshot)
                    }
                } else {
                    completion(screenshots: images)
                }
            }
        }

        takeScreenshotAtPoint(point: points[counter]) { (screenshot) -> Void in
            counter += 1
            images.append(screenshot)
        }

    }

    private func getScreenshotRects() -> (points:[[CGPoint]], frames:[[CGRect]]) {

        let vanillaBounds = CGRect(x: 0, y: 0, width: self.bounds.size.width, height: self.bounds.size.height)

        let xPartial = contentSize.width % bounds.size.width
        let yPartial = contentSize.height % bounds.size.height

        let xSlices = Int((contentSize.width - xPartial) / bounds.size.width)
        let ySlices = Int((contentSize.height - yPartial) / bounds.size.height)

        var currentOffset = CGPoint(x: 0, y: 0)

        var offsets : [[CGPoint]] = []
        var rects : [[CGRect]] = []

        var xSlicesWithPartial : Int = xSlices

        if xPartial > 0 {
            xSlicesWithPartial += 1
        }

        var ySlicesWithPartial : Int = ySlices

        if yPartial > 0 {
            ySlicesWithPartial += 1
        }

        for y in 0..<ySlicesWithPartial {

            var offsetRow : [CGPoint] = []
            var rectRow : [CGRect] = []
            currentOffset.x = 0

            for x in 0..<xSlicesWithPartial {

                if y == ySlices && x == xSlices {
                    let rect = CGRect(x: bounds.width - xPartial, y: bounds.height - yPartial, width: xPartial, height: yPartial)
                    rectRow.append(rect)

                } else if y == ySlices {
                    let rect = CGRect(x: 0, y: bounds.height - yPartial, width: bounds.width, height: yPartial)
                    rectRow.append(rect)

                } else if x == xSlices {
                    let rect = CGRect(x: bounds.width - xPartial, y: 0, width: xPartial, height: bounds.height)
                    rectRow.append(rect)

                } else {
                    rectRow.append(vanillaBounds)
                }

                offsetRow.append(currentOffset)

                if x == xSlices {
                    currentOffset.x = contentSize.width - bounds.size.width
                } else {
                    currentOffset.x = currentOffset.x + bounds.size.width
                }
            }
            if y == ySlices {
                currentOffset.y = contentSize.height - bounds.size.height
            } else {
                currentOffset.y = currentOffset.y + bounds.size.height
            }

            offsets.append(offsetRow)
            rects.append(rectRow)

        }

        return (points:offsets, frames:rects)

    }

    private func takeScreenshotAtPoint(point point_I: CGPoint, completion: (screenshot: UIImage) -> Void) {
        let rect = CGRect(x: 0, y: 0, width: self.bounds.size.width, height: self.bounds.size.height)
        let currentOffset = contentOffset
        setContentOffset(point_I, animated: false)

        delay(0.001) {

            UIGraphicsBeginImageContextWithOptions(rect.size, false, UIScreen.mainScreen().scale)
            self.drawViewHierarchyInRect(rect, afterScreenUpdates: true)
            let image = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()


            self.setContentOffset(currentOffset, animated: false)
            completion(screenshot: image)
        }
    }

    private func delay(delay:Double, closure:()->()) {
        dispatch_after(
            dispatch_time(
                DISPATCH_TIME_NOW,
                Int64(delay * Double(NSEC_PER_SEC))
            ),
            dispatch_get_main_queue(), closure)
    }


    private func crop(image image_I:UIImage, toRect rect:CGRect) -> UIImage? {

        guard let imageRef: CGImageRef = CGImageCreateWithImageInRect(image_I.CGImage, rect) else {
            return nil
        }
        return UIImage(CGImage:imageRef)
    }

    private func stitchImages(images images_I: [[UIImage]], finalSize : CGSize) -> UIImage? {

        let finalRect = CGRect(x: 0, y: 0, width: finalSize.width, height: finalSize.height)

        guard images_I.count > 0 else {
            return nil
        }

        UIGraphicsBeginImageContext(finalRect.size)

        var offsetY : CGFloat = 0

        for imageRow in images_I {

            var offsetX : CGFloat = 0

            for image in imageRow {

                let width = image.size.width
                let height = image.size.height


                let rect = CGRect(x: offsetX, y: offsetY, width: width, height: height)
                image.drawInRect(rect)

                offsetX += width

            }

            offsetX = 0

            if let firstimage = imageRow.first {
                offsetY += firstimage.size.height
            } // maybe add error handling here
        }

        let stitchedImages = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        return stitchedImages
    }
}

extension UIScrollView : ScrollViewImager {

}

答案 1 :(得分:0)

使用UIKit图形函数将UICollectionView 的位图数据绘制到UIImage中。然后你将有一个UIImage,你可以保存到磁盘或用它做任何你需要的。这样的事情应该有效:

// your collection view
@IBOutlet weak var myCollectionView: UICollectionView!

//...

let image: UIImage!

// draw your UICollectionView into a UIImage
UIGraphicsBeginImageContext(myCollectionView.frame.size) 

myCollectionView.layer.renderInContext(UIGraphicsGetCurrentContext()!)

image = UIGraphicsGetImageFromCurrentImageContext()  

UIGraphicsEndImageContext()

答案 2 :(得分:0)

为Swift 4制作UICollectionView的屏幕截图

func makeScreenShotToShare()-> UIImage{
        UIGraphicsBeginImageContextWithOptions(CGSize.init(width: self.colHistory.contentSize.width, height: self.colHistory.contentSize.height + 84.0), false, 0)
        colHistory.scrollToItem(at: IndexPath.init(row: 0, section: 0), at: .top, animated: false)
        colHistory.layer.render(in: UIGraphicsGetCurrentContext()!)
        let row = colHistory.numberOfItems(inSection: 0)
        let numberofRowthatShowinscreen = self.colHistory.size.height / (self.arrHistoryData.count == 1 ? 130 : 220)
        let scrollCount = row / Int(numberofRowthatShowinscreen)

        for  i in 0..<scrollCount {
            colHistory.scrollToItem(at: IndexPath.init(row: (i+1)*Int(numberofRowthatShowinscreen), section: 0), at: .top, animated: false)
            colHistory.layer.render(in: UIGraphicsGetCurrentContext()!)
        }

        let image:UIImage = UIGraphicsGetImageFromCurrentImageContext()!
        UIGraphicsEndImageContext();
        return image
    }