根据
https://juejin.cn/post/6940140043042291748 的缩放效果改了一个,你试试效果
```Swift
import UIKit
class ViewController: UIViewController {
private let margin: CGFloat = 20
private var itemW: CGFloat = .zero
private let cellID = "baseCellID"
private let cellCount = 100
private var collectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
setUpView()
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
}
func setUpView() {
let layout = ZGFlowLayout()
let collH: CGFloat = 200
let itemH = collH - margin * 2
itemW = view.bounds.width - margin * 2 - 100
layout.itemSize = CGSize(width: itemW, height: itemH)
layout.minimumLineSpacing = margin
layout.scrollDirection = .horizontal
collectionView = UICollectionView(frame: CGRect(x: 0, y: 180, width: view.bounds.width, height: collH), collectionViewLayout: layout)
collectionView.backgroundColor = .black
collectionView.showsHorizontalScrollIndicator = false
collectionView.dataSource = self
collectionView.delegate = self
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: cellID)
view.addSubview(collectionView)
scrollTo(index: cellCount/2)
}
}
extension ViewController: UICollectionViewDelegate, UICollectionViewDataSource{
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return cellCount
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellID, for: indexPath)
let colors: [UIColor] = [.red, .yellow, .blue]
cell.backgroundColor = colors[indexPath.item % 3]
return cell
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
let scrollStop = !scrollView.isTracking && !scrollView.isDragging && !scrollView.isDecelerating
guard scrollStop else { return }
ZGScrollViewDidEndScroll(scrollView: scrollView)
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
//防止滚动到最后或者最前,如果觉得改变时突兀,可以增加 cellCount
let page = getCurrentPage(scrollView: scrollView)
if page >= 95 || page <= 5 {
scrollTo(index: page%3 + cellCount+1)
}
}
private func ZGScrollViewDidEndScroll(scrollView: UIScrollView) {
let page = getCurrentPage(scrollView: scrollView)
scrollTo(index: page%3 + cellCount+1)
}
private func scrollTo(index: Int){
collectionView.scrollToItem(at: IndexPath(item: index, section: 0), at: .centeredHorizontally, animated: false)
}
private func getCurrentPage(scrollView: UIScrollView) -> Int{
//第一个 page 偏移量会少了多显示出来的一半,不使用之后的计算,直接判定为 0
var page: CGFloat = 0
if scrollView.contentOffset.x > 0 {
//计算单次滑动的偏移量
let scrollW = scrollView.frame.width
//显示的多出一半的宽度
let half = (scrollW - itemW)/2
//除第一个外其余每次滑动的偏移量
let eachOffset = (itemW+margin)
//第一个 cell 的偏移量
let firstOffset = eachOffset-half
page = (scrollView.contentOffset.x-firstOffset)/(eachOffset) + 1
}
return Int(page)
}
}
class ZGFlowLayout: UICollectionViewFlowLayout {
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
let attributes = super.layoutAttributesForElements(in: rect)
let centerX = collectionView!.contentOffset.x + collectionView!.bounds.width / 2
attributes?.forEach({ (attr) in
let pad = abs(centerX - attr.center.x)
let factor = 0.0009
let scale = 1 / (1 + pad * CGFloat(factor))
attr.transform = CGAffineTransform(scaleX: scale, y: scale)
})
return attributes
}
override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
var targetPoint = proposedContentOffset
let centerX = proposedContentOffset.x + collectionView!.bounds.width / 2
let attrs = self.layoutAttributesForElements(in: CGRect(x: proposedContentOffset.x, y: proposedContentOffset.y, width: collectionView!.bounds.size.width, height: collectionView!.bounds.size.height))
var moveDistance: CGFloat = CGFloat(MAXFLOAT)
attrs!.forEach { (attr) in
if abs(attr.center.x - centerX) < abs(moveDistance) {
moveDistance = attr.center.x - centerX
}
}
if targetPoint.x > 0 && targetPoint.x < collectionViewContentSize.width - collectionView!.bounds.width {
targetPoint.x += moveDistance
}
return targetPoint
}
override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
return true
}
override var collectionViewContentSize: CGSize {
return CGSize(width: sectionInset.left + sectionInset.right + (CGFloat(collectionView!.numberOfItems(inSection: 0)) * (itemSize.width + minimumLineSpacing)) - minimumLineSpacing, height: 0)
}
}
```