Self Sizing Cells on UICollectionView

19 Jun 2015

My goal was to do a home page with layout like Pinterest.

Screen Shot 2015-06-19 at 8.55.25 AM

After some research I found this projects; PinterestAnimator and PinterestSwift. These really helped me about collection view layout, especially CHTCollectionViewWaterfallLayout. However there is still one problem called self-sizing.

So I searched more and found this fantastic extension on Alamofire in order to download images, thanks to Ray Wenderlich.


    extension Alamofire.Request {
        class func imageResponseSerializer() -> Serializer {
            return { request, response, data in
                if let data = data {
                    let image = UIImage(data: data)
                    return (image, nil)
                }
                return (nil, nil)
            }
        }    

        func responseImage(completionHandler: (NSURLRequest, NSHTTPURLResponse?, UIImage?, NSError?) -> Void) -> Self {
            return response(serializer: Request.imageResponseSerializer(), completionHandler: {
                (request, response, image, error) in
                completionHandler(request, response, image as? UIImage, error)
            })
        }
    }

Image size is accessible once it's downloaded but we know its width will be (view.size-3*inset)/columnNumber. Therefore we can filter image to that size in order to achieve faster loading time. Here is the code:


    let item = items[indexPath.row]
            
    // Prepare for re-use
    cell.request?.cancel()
    cell.imageView.image = nil // Caching can be implemented here
            
    let imageScale = UIScreen.mainScreen().scale
    let imagePixel = Int(cellWidth * imageScale)
    let filterURLString = "http://cdn.filter.to/\(imagePixel)x\(imagePixel)/"
    // We should delete "http://" of imageURLString in order to use filtering
            
    if
    let imageURLString = item.imageURLString,
    let rangeOfURLString = imageURLString.rangeOfString("//", options: .allZeros, range: nil, locale: nil),
    let imageURL = NSURL(string: filterURLString+imageURLString.substringFromIndex(advance(rangeOfURLString.startIndex,2)))
    {
        cell.request = Alamofire.request(.GET, imageURL, parameters: nil, encoding: .URL).responseImage({
            (_, _, image, error) -> Void in
            if let image = image where error == nil {
                // Resize cell
                cell.imageView.image = image
                cell.title = item.title
                cell.subtitle = item.subtitle
                let imageViewHeight = self.cellWidth * image.ratio
                let extraHeight = cell.titleLabel.frame.height + cell.subtitleLabel.frame.height
                item.estimatedCellSize = CGSize(width: self.cellWidth, height: imageViewHeight + extraHeight)
                // Perform updates
                collectionView.performBatchUpdates(nil, completion: nil)
            }
        })
    }

Result: iOS Simulator Screen Shot Jun 19, 2015, 1.57.15 PM

 

You can find the project here.