Handle scrollview size in UICollectionViewCell Handle scrollview size in UICollectionViewCell ios ios

Handle scrollview size in UICollectionViewCell


Well First lets start with UIViewController that is holding your UICollectionView:

Define a variable to hold the collection view layout:

var flowLayout:UICollectionViewFlowLayout = UICollectionViewFlowLayout()

You will have to override viewWillLayoutSubviews and this is going to handle the collectionView size.

override func viewWillLayoutSubviews() {    super.viewWillLayoutSubviews()    flowLayout.itemSize = CGSize(width: view.frame.width, height:view.frame.height)}

Also you will need to override viewDidLayoutSubviews to handle the size of each new cell to set it to default size:

    override func viewDidLayoutSubviews() {        if let currentCell = imageCollectionView.cellForItemAtIndexPath(desiredIndexPath) as? GalleryCell {            currentCell.configureForNewImage()        }}

in ViewDidLoad setup the collectionView to be horizontal with flow layout:

    // Set up flow layout    flowLayout.scrollDirection = UICollectionViewScrollDirection.Horizontal    flowLayout.minimumInteritemSpacing = 0    flowLayout.minimumLineSpacing = 0    // Set up collection view    imageCollectionView = UICollectionView(frame: CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height), collectionViewLayout: flowLayout)    imageCollectionView.translatesAutoresizingMaskIntoConstraints = false    imageCollectionView.registerClass(GalleryCell.self, forCellWithReuseIdentifier: "GalleryCell")    imageCollectionView.dataSource = self    imageCollectionView.delegate = self    imageCollectionView.pagingEnabled = true    view.addSubview(imageCollectionView)    imageCollectionView.contentSize = CGSize(width: 1000.0, height: 1.0)

In your UICollectionView method cellForItemAtIndexPath load the image only without setting anything:

 cell.image = UIImage(named: array[indexPath.row])

Now lets move to GalleryCell class and to handle scrollView when zooming:

class GalleryCell: UICollectionViewCell, UIScrollViewDelegate {    var image:UIImage? {        didSet {            configureForNewImage()        }    }     var scrollView: UIScrollView     let imageView: UIImageView   override init(frame: CGRect) {        imageView = UIImageView()        imageView.translatesAutoresizingMaskIntoConstraints = false        scrollView = UIScrollView(frame: frame)        scrollView.translatesAutoresizingMaskIntoConstraints = false        super.init(frame: frame)        contentView.addSubview(scrollView)        contentView.addConstraints(scrollViewConstraints)        scrollView.addSubview(imageView)        scrollView.delegate = self        scrollView.maximumZoomScale = 4    }    required public init?(coder aDecoder: NSCoder) {        fatalError("init(coder:) has not been implemented")    }    internal func configureForNewImage() {        imageView.image = image        imageView.sizeToFit()        setZoomScale()        scrollViewDidZoom(scrollView)    }    public func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView? {        return imageView    }    public func scrollViewDidZoom(scrollView: UIScrollView) {        let imageViewSize = imageView.frame.size        let scrollViewSize = scrollView.bounds.size        let verticalPadding = imageViewSize.height < scrollViewSize.height ? (scrollViewSize.height - imageViewSize.height) / 2 : 0        let horizontalPadding = imageViewSize.width < scrollViewSize.width ? (scrollViewSize.width - imageViewSize.width) / 2 : 0        if verticalPadding >= 0 {            // Center the image on screen            scrollView.contentInset = UIEdgeInsets(top: verticalPadding, left: horizontalPadding, bottom: verticalPadding, right: horizontalPadding)        } else {            // Limit the image panning to the screen bounds            scrollView.contentSize = imageViewSize        }}

I've tested it with example and it should solve your issue with scrollview and @Spencevail explained mostly why it's being caused !


You need to set the contentInset on your scrollview. What's happening is The contentSize of the UIScrollView is originally set to match the screen size with the image inside of that. As you zoom in on the scrollview, the contentSize expands proportionately, so those black areas above and below the photos when you're zoomed all the way out expand as you zoom in. In other words You're expanding the area above and below where your image can go. If you adjust the contentInset it will bring in that dead area and not allow the scrollview to move the image out of the window.

public func scrollViewDidZoom(scrollView: UIScrollView) {    let imageViewSize = imageView.frame.size    let scrollViewSize = scrollView.bounds.size    let verticalPadding = imageViewSize.height < scrollViewSize.height ? (scrollViewSize.height - imageViewSize.height) / 2 : 0    let horizontalPadding = imageViewSize.width < scrollViewSize.width ? (scrollViewSize.width - imageViewSize.width) / 2 : 0    if verticalPadding >= 0 {        // Center the image on screen        scrollView.contentInset = UIEdgeInsets(top: verticalPadding, left: horizontalPadding, bottom: verticalPadding, right: horizontalPadding)    } else {        // Limit the image panning to the screen bounds        scrollView.contentSize = imageViewSize    }}

This looks almost the same as an open source Cocoapod I help manage, SwiftPhotoGallery. Take a look at the code for the SwiftPhotoGalleryCell and you should get a pretty good idea of how to do this. (Feel free to just use the cocoapod too if you want!)