控制器代码
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 // } }