1. 程式人生 > 其它 >自定義UICollectionViewFlowLayout實現橫向滾動時,離中心點越近,item越大,離中心店越遠,item越小的效果

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