Я решил эту проблему с помощью UIScrollView и UICollectionViewLayout подкласса.
1) поместил UIScrollView поверх UICollectionView с таким же фреймом.
self.view.addSubview(scrollView)
scrollView.addSubview(dummyViewForZooming)
scrollView.frame = collectionView.frame
scrollView.bouncesZoom = false
scrollView.minimumZoomScale = 0.5
scrollView.maximumZoomScale = 3.0
2) Установите contentSizeUIScrollView и zoomingView должны совпадать с UICollectionView
override func viewDidLayoutSubviews() {
super.viewWillLayoutSubviews()
scrollView.contentSize = layout.collectionViewContentSize
dummyViewForZooming.frame = CGRect(origin: .zero, size: layout.collectionViewContentSize)
scrollView.frame = collectionView.frame
}
3) Удалите все распознаватели жестов из UICollectionView и добавьте делегат для UIScrollView.Добавьте распознаватель жестов касания к UIScrollview
collectionView.gestureRecognizers?.forEach {
collectionView.removeGestureRecognizer($0)
}
let tap = UITapGestureRecognizer.init(target: self, action: #selector(scrollViewWasTapped(sender:)))
tap.numberOfTapsRequired = 1
scrollView.addGestureRecognizer(tap)
scrollView.delegate = self
4) Когда ScrollView прокручивает или увеличивает масштаб, установите contentOffset UICollectionView таким же, как ScrollView contentOffset, установите layoutScale вашего UICollectionViewLayout в качестве zoomscaleи сделать недействительным макет.
func scrollViewDidZoom(_ scrollView: UIScrollView) {
if let layout = self.layout, layout.getScale() != scrollView.zoomScale {
layout.layoutScale = scrollView.zoomScale
self.layout.invalidateLayout()
collectionView.contentOffset = scrollView.contentOffset
}
}
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return dummyViewForZooming
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
collectionView.contentOffset = scrollView.contentOffset
}
5) переопределить метод prepare в UICollectionViewLayout, отсканировать все ваши layoutAttributes и установить преобразование:
attribute.transformedFrame = attribute.originalFrame.scale(layoutScale)
let ts = CGAffineTransform(scaleX: layoutScale, y: layoutScale)
attribute.transform = ts
let xDifference = attribute.frame.origin.x - attribute.transformedFrame.origin.x
let yDifference = attribute.frame.origin.y - attribute.transformedFrame.origin.y
let t1 = CGAffineTransform(translationX: -xDifference, y: -yDifference)
let t = ts.concatenating(t1)
attribute.transform = t
6) убедиться, что вы масштабируете размер содержимого collectionView:
override var collectionViewContentSize: CGSize {
return CGSize(width: width * layoutScale, height: height * layoutScale)
}
7) Перехватывать касания из распознавателя жестов касания и преобразовывать отображаемое местоположение в точку в представлении коллекции, затем вы можете получить indexPath этой ячейки с помощью indexPathForItem (point :) и выбрать ячейку илипередавать события базовым представлениям ячейки и т. д.
надеюсь, это поможет