自定义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
//    }
}

  

  

  

 

posted on 2021-06-15 20:54  大圣ios博客  阅读(647)  评论(0编辑  收藏  举报