我已经使用 UIScrollView 和 UICollectionViewLayout 子类解决了这个问题。
1) 在 UICollectionView 的顶部放置一个 UIScrollView 与相同的框架。
self.view.addSubview(scrollView)
scrollView.addSubview(dummyViewForZooming)
scrollView.frame = collectionView.frame
scrollView.bouncesZoom = false
scrollView.minimumZoomScale = 0.5
scrollView.maximumZoomScale = 3.0
2) 设置 UIScrollView 和 zoomingView 的 contentSize 与 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 滚动或缩放时,将 UICollectionView 的 contentOffset 设置为与 ScrollView contentOffset 相同,将你的 UICollectionViewLayout 的 layoutScale 设置为 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) 覆盖 UICollectionViewLayout 中的 prepare 方法,扫描所有 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) 从点击手势识别器拦截点击并将视图中的位置转换为集合视图中的一个点,然后您可以使用 indexPathForItem(point:) 获取该单元格的 indexPath 并选择该单元格或将事件传递给单元格的底层视图等。
希望对你有帮助