自定义UICollectionViewFlowLayout实现横向滚动时,离中心点越近,item越大,离中心店越远,item越小的效果
控制器代码
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(collectionView)
}
lazy var collectionView:UICollectionView = {
let layout = Layer()
layout.itemSize = CGSize(width: 160, height: 160)
layout.scrollDirection = .horizontal
let margin = (UIScreen.main.bounds.size.width - 160) * 0.5
layout.sectionInset = UIEdgeInsets(top: 0, left: margin, bottom: 0, right: margin)
layout.minimumLineSpacing = 50
let collectionView = UICollectionView(frame: CGRect(x: 0, y: 200, width: UIScreen.main.bounds.size.width, height: 200), collectionViewLayout: layout)
collectionView.backgroundColor = .purple
collectionView.delegate = self
collectionView.dataSource = self
collectionView.register(CollectionViewCell.self, forCellWithReuseIdentifier: "reuseId")
return collectionView
}()
}
自定义UICollectionViewFlowLayout
class Layer: UICollectionViewFlowLayout {
/**
什么时候调用:collectionView第一次布局的时候调用 还有刷新的时候调用
有什么作用:计算cell 的布局 条件:cell 位置固定不变的时候
*/
// open override func prepare(){
// super.prepare()
// print("调用")
// }
/**
UICollectionViewLayoutAttributes 确定cell的尺寸的
一个 UICollectionViewLayoutAttributes 对象对应这一个cell
是要拿到这个类 就相当于拿到cell
*/
//作用:返回cell 的尺寸
open override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]?{
// print(rect)
//1.获取当前显示的区域
let attrs = super.layoutAttributesForElements(in: self.collectionView?.bounds ?? CGRect.zero)
// print(attrs)
//2.获取当前显示的cell 的布局
// 效果: 越靠近中心点就越大
if let attrs = attrs {
for attr in attrs {
//2.1求cell 与中心点的距离
let margin = abs((attr.center.x - (self.collectionView?.contentOffset.x ?? 0) - ((self.collectionView?.frame.size.width ?? 0) * 0.5)))
//2.2计算比例
let scale = 1 - (margin / ((self.collectionView?.frame.size.width ?? 0) * 0.5) * 0.25)
attr.transform = CGAffineTransform(scaleX: scale, y: scale)
}
}
return attrs
}
/**
在滚动collectionView 的时候是否允许布局
返回YES 每次都会刷新布局
*/
override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
return true
}
/**
什么时候调用: 用户手指松开的时候
作用:确定最终偏移量
*/
override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
print("确定偏移量")
//最终偏移量 是否等于手指离开的偏移量(不等于)
var finalPoint = super.targetContentOffset(forProposedContentOffset: proposedContentOffset, withScrollingVelocity: velocity)
// print(finalPoint, self.collectionView?.contentOffset)
//1. 获取最终显示区域
let collectionW = self.collectionView?.frame.size.width ?? 0
let finalRect = CGRect(x: finalPoint.x, y: 0, width: collectionW, height: CGFloat.greatestFiniteMagnitude)
//获取最终显示cell
let attrs = super.layoutAttributesForElements(in: finalRect)
if let attrs = attrs {
var minDetal = CGFloat.greatestFiniteMagnitude
for attr in attrs {
var detal = (attr.center.x - (finalPoint.x ?? 0) - ((self.collectionView?.frame.size.width ?? 0) * 0.5))
//获取中心点的距离
if abs(detal) < abs(minDetal) {
minDetal = detal
}
}
finalPoint.x += minDetal
}
return finalPoint
}
/**
计算collectionView 的滚动范围
*/
// override var collectionViewContentSize: CGSize{
// return super.collectionViewContentSize
// }
}