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)
}
}