Please, tell me the best way to "zoom in/out" UICollectionView
and change size of UICollectionViewCell
. I'm using a UIPinchGestureRecognizer
now: When UICollectionView
is "zoom in" and "zoom out", there are serious delays and freezing.
How can I get rid of friezes when I perform a PinchGestureRecognizer?
Here is implementation code of UIPinchGestureRecognizer in UICollectionViewController:
class BlocksCollectionViewController: UICollectionViewController, UIGestureRecognizerDelegate {
private var senderStartSize = CGFloat()
private var senderNormalPosition = CGSize()
override func viewDidLoad() {
super.viewDidLoad()
let pinchRecognizer = UIPinchGestureRecognizer(target: self, action: #selector(handlePinch(_:)))
pinchRecognizer.delegate = self
collectionView?.addGestureRecognizer(pinchRecognizer)
}
@objc func handlePinch(_ sender: UIPinchGestureRecognizer) {
guard let collection = collectionView else { return }
guard let layout = collection.collectionViewLayout as? CustomCollectionViewLayout else { return }
switch sender.state {
case .began:
senderStartSize = layout.cellSize
case .changed:
layout.cellSize = senderStartSize * sender.scale
layout.invalidateLayout()
default:
break
}
}
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
}
The code below is сustom CollectionViewLayout:
class CustomCollectionViewLayout: UICollectionViewLayout {
private var cellAttributes: [IndexPath: UICollectionViewLayoutAttributes] = [:]
var cellSize: CGFloat = 7
private var contentSize = CGSize.zero
override var collectionViewContentSize: CGSize {
return self.contentSize
}
override func prepare() {
guard let collection = collectionView else { return }
for section in 0...collection.numberOfSections - 2 {
for item in 0...collection.numberOfItems(inSection: section) - 2 {
let cellIndex = IndexPath(item: item, section: section)
let xPos = CGFloat(item) * cellSize
let yPos = CGFloat(section) * cellSize
let attributes = UICollectionViewLayoutAttributes(forCellWith: cellIndex)
attributes.frame = CGRect(x: xPos, y: yPos, width: cellSize, height: cellSize)
cellAttributes[cellIndex] = attributes
}
}
let contentWidth = CGFloat(collection.numberOfItems(inSection: 0)) * cellSize
let contentHeight = CGFloat(collection.numberOfSections) * cellSize
contentSize = CGSize(width: contentWidth, height: contentHeight)
let centerOffsetX = (collection.contentSize.width - collection.frame.size.width) / 2
let centerOffsetY = (collection.contentSize.height - collection.frame.size.height) / 2
let centerPoint = CGPoint(x: centerOffsetX, y: centerOffsetY)
collection.setContentOffset(centerPoint, animated: false)
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
var attributesInRect = [UICollectionViewLayoutAttributes]()
for cellAttributes in cellAttributes.values {
if rect.intersects(cellAttributes.frame) {
attributesInRect.append(cellAttributes)
}
}
return attributesInRect
}
override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
return cellAttributes[indexPath]
}
}
Due to the fact that there are a lot of UICollectionViewCells in my collection, the best way is this:
1) Place UICollectionView on a containerView (simple UIView), and put this containerView on UIScrollView.
I limited zoom:
scrollView.minimumZoomScale = 1
scrollView.maximumZoomScale = 6
2) And used functions of UIScrollViewDelegate:
func scrollViewDidZoom(_ scrollView: UIScrollView) {
// Code for processing zoom - scrollView.zoomScale,
// contentOffset, contentSize etc....
}
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return containerView
}