Zoom CollectionView inside ScrollView

47 Views Asked by At

I want to zoom a collectionView inside a scrollView, but when I zoom the scrollView, the contentOffset of the scrollView doesn't change. Therefore, I can't scroll to the top of the collectionView when zoomed. How can I address this situation? I want to smoothly zoom and scroll, similar to reading a PDF.

Here is my code

import UIKit

class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {
    
    static let cellId = "CellId"

    var collectionView: UICollectionView?
    var scrollView: UIScrollView?
    override func viewDidLoad() {
        super.viewDidLoad()
        let layout = UICollectionViewFlowLayout()
        layout.itemSize = CGSize(width: view.frame.width, height: view.frame.height)
        layout.scrollDirection = .vertical
        layout.minimumLineSpacing = 0
        layout.minimumInteritemSpacing = 0
        layout.sectionInset = UIEdgeInsetsMake(0,0,0,0)



        collectionView = UICollectionView(frame: CGRect(origin: .zero, size: self.view.frame.size), collectionViewLayout: layout)

        collectionView!.register(ZoomableCell.self, forCellWithReuseIdentifier: "singleCell")
        collectionView!.delegate = self
        collectionView!.dataSource = self
        scrollView = UIScrollView(frame: self.view.frame)
        self.view.addSubview(scrollView!)
        scrollView!.addSubview(collectionView!)
        scrollView!.delegate = self
        scrollView!.maximumZoomScale = 3
        let doubleTapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(doubleTapGesture(_:)))
        doubleTapGestureRecognizer.numberOfTapsRequired = 2
        collectionView!.addGestureRecognizer(doubleTapGestureRecognizer)

    }
    @objc
    private func doubleTapGesture(_ sender: UITapGestureRecognizer) {
        if ( self.scrollView!.zoomScale > 1.0) {
            self.scrollView!.setZoomScale(1.0, animated: true)
        } else {
            let zoomRect:CGRect = self.zoomRectForScale(scale: 3.0 / 2 , center: sender.location(in: sender.view))
            self.scrollView!.zoom(to: zoomRect, animated: true)
        }

    }

    func zoomRectForScale(scale:CGFloat, center: CGPoint) -> CGRect{
        var zoomRect: CGRect = CGRect()
        // this point (center) is relative to collection view, need convert back to contentView
        let contentW = view.frame.width
        let contentH = view.frame.height
        let newX = center.x - contentW * floor(center.x / contentW)
        let newPoint = CGPoint(x: newX, y: center.y)
        zoomRect.size.height = contentH / scale
        zoomRect.size.width = contentW / scale
        zoomRect.origin.x = newPoint.x - zoomRect.size.width / 2.0
        zoomRect.origin.y = newPoint.y - zoomRect.size.height / 2.0
        return zoomRect
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 1
    }
    
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 10
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell:ZoomableCell = collectionView.dequeueReusableCell(withReuseIdentifier: "singleCell", for: indexPath) as! ZoomableCell

        let image = UIImage(named:"test")
        cell.imageView.image = image
        return cell
    }

}

extension ViewController: UIScrollViewDelegate {
    func viewForZooming(in scrollView: UIScrollView) -> UIView? {
        return collectionView
    }
}

class ZoomableCell: UICollectionViewCell {
    var imageView:UIImageView!

    required init(coder aDecoder:NSCoder){
        super.init(coder: aDecoder)!
    }

    override init(frame:CGRect){
        super.init(frame:frame)

        setup()
    }

    func setup() {
        //imageViewを生成
        imageView =  UIImageView()
        imageView.frame = CGRect(x:0,y:0,width:self.frame.width,height:self.frame.height)
        contentView.addSubview(imageView)

    }

}


0

There are 0 best solutions below