64-Swift之流水布局(UICollectionView)

一 、 流水布局的介紹

在App 的開發(fā)中。流水布局是一種顯示形式,它類似與生產(chǎn)線的傳送帶和商品的組合圖顯示的用戶的視野內(nèi)。流水布局又有人稱畫廊布局或畫廊效果。

二、 本簡(jiǎn)書的樣本例子如下:

4.gif

三 、 如何編寫流水布局呢?

我們實(shí)現(xiàn)流水布局的控件選擇有好多。我們這里選擇 UICollectionView 為實(shí)現(xiàn)流水布局的底層組件。要使用 UICollectionView 來實(shí)現(xiàn)流水布局,我們就要重新定義 UICollectionView 的布局文件。我們要繼承 UICollectionViewFlowLayout ,并且要重寫 UICollectionViewFlowLayout 類的幾個(gè)方法。如下:

  • func prepare() ===》 : 重新初始化Cell的布局。每次刷新將重新調(diào)用該方法。在重寫的時(shí)候,要首先調(diào)用該方法的父類的該方法。

  • func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) ===》 : 當(dāng)CollectionView的顯示范圍發(fā)生變化的時(shí)候,是否需要重新布局。如果重新布局就會(huì)調(diào)用 1. func prepare() 2. override func layoutAttributesForElements(in rect: CGRect) 兩個(gè)方法.

  • func layoutAttributesForElements(in rect: CGRect) ===》 : 返回設(shè)置好的布局?jǐn)?shù)組。

  • func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint ===》 保持Cell每次滑動(dòng)后停止在UICollectionView的中間。

四、 流水布局重新定義和一些方法的重新

1、 override func prepare() 的重寫

// MARK: 布局初始化
override func prepare() {
    super.prepare()
    // 設(shè)置Cell的位置
    let marginX = ( (self.collectionView?.frame.size.width)! - self.itemSize.width ) * 0.5
    self.collectionView?.contentInset = UIEdgeInsets.init(top: 0, left: marginX, bottom: 0, right: marginX)
}

2 、 func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) 的方法的重寫

// MARK: 當(dāng)CollectionView的顯示范圍發(fā)生變化的時(shí)候,是否需要重新布局。如果重新布局就會(huì)調(diào)用 1. func prepare()  2. override func layoutAttributesForElements(in rect: CGRect) 兩個(gè)方法
override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
     return true
}

3、 func layoutAttributesForElements(in rect: CGRect) 的重寫

// MARK: 返回設(shè)置好的布局?jǐn)?shù)組
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
    // 創(chuàng)建系統(tǒng)默認(rèn)的 UICollectionViewLayoutAttributes
    let DefaultAttributes = super.layoutAttributesForElements(in: rect)
    // 計(jì)算Item在UICollectionView上的 X 軸的大小
    let CollectionViewCenterX = (self.collectionView?.contentOffset.x)! + (self.collectionView?.frame.width)! * 0.5
    for item in DefaultAttributes! {
        // 計(jì)算Cell的中心點(diǎn)距離CollectionView的中心點(diǎn)的距離(如果Cell在中間,我們看到的就是不縮放的效果)
        let Delta = abs(item.center.x - CollectionViewCenterX)
        // 計(jì)算Cell 的縮放值
        let Scal = 1.0 - Delta / (self.collectionView?.frame.width)!
        // 設(shè)置Cell 滾動(dòng)時(shí)的縮放比例
        item.transform = CGAffineTransform(scaleX: Scal, y: Scal)
    }
    return DefaultAttributes
}

4、 func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint 方法的重寫

// MARK: 保持Cell每次滑動(dòng)后停止在UICollectionView的中間
override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
    // 計(jì)算展示Cell的矩形框大小
    var rect = CGRect.init()
    rect.origin.y = 0
    rect.origin.x = proposedContentOffset.x
    rect.size = (self.collectionView?.frame.size)!
    
    var ContentOffset = proposedContentOffset.x
    // 計(jì)算CollectionView 中點(diǎn)Cell的偏移的 X 坐標(biāo)值
    let CollectionViewCenterX = proposedContentOffset.x + (self.collectionView?.frame.width)! * 0.5
    
    var minDelta = MAXFLOAT
    for item:UICollectionViewLayoutAttributes in super.layoutAttributesForElements(in: rect)!{
        if CGFloat(abs(minDelta)) > abs(item.center.x - CollectionViewCenterX) {
            minDelta = Float(item.center.x - CollectionViewCenterX)
        }
    }
    ContentOffset += CGFloat(minDelta)
    return CGPoint.init(x: ContentOffset, y: proposedContentOffset.y)
}

五、 流水布局的使用

1、 創(chuàng)建UICollectionView對(duì)象

// MARK: 創(chuàng)建UICollectionView對(duì)象
func createCollectionView() -> Void{
    // TODO: 創(chuàng)建布局對(duì)象
    let FlowingwaterLayout = FlowingwaterCollectionViewLayout.init()
    // TDOD: 設(shè)置方向
    FlowingwaterLayout.scrollDirection = .horizontal
    FlowingwaterLayout.itemSize = CGSize.init(width: 200, height: 380)
    
    let FlowingwaterCollectionView = UICollectionView.init(frame: CGRect.init(x: 0, y: 100, width: view.frame.width, height: 400), collectionViewLayout: FlowingwaterLayout)
    // TODO: 設(shè)置代理
    FlowingwaterCollectionView.delegate = self
    FlowingwaterCollectionView.dataSource = self
    // TODO: 渲染到視圖
    self.view.addSubview(FlowingwaterCollectionView)
    
    // TODO: 注冊(cè)Cell
    FlowingwaterCollectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "NetWork小賤")
    
}

2、 UICollectionViewDelegate / UICollectionViewDataSource / UICollectionViewFlowLayout 的代理實(shí)現(xiàn)

// MARK: UICollectionViewDelegate / UICollectionViewDataSource / UICollectionViewFlowLayout 的代理實(shí)現(xiàn)

// TODO: 返回Cell的個(gè)數(shù)
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return dataArray.count
}

// TODO: 創(chuàng)建Cell
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    // 獲取Cell
    let Cell = collectionView.dequeueReusableCell(withReuseIdentifier: "NetWork小賤", for: indexPath)
    Cell.contentView.backgroundColor = UIColor.white
    for item in Cell.contentView.subviews {
        item.removeFromSuperview()
    }
    // 圖像
    let imageV = UIImageView.init(frame: CGRect.init(x: 0, y: 0, width: Cell.bounds.width, height: Cell.bounds.height - 60))
    imageV.contentMode = .scaleToFill
    imageV.image = UIImage.init(named:(dataArray![indexPath.row] as! NSDictionary)["image"] as! String)
    Cell.contentView.addSubview(imageV)
    
    // 標(biāo)題
    let titleL = UILabel.init(frame: CGRect.init(x: 5, y: imageV.frame.maxY + 5, width: Cell.bounds.width - 10, height: 30))
    titleL.font = UIFont.systemFont(ofSize: 18)
    titleL.text = ((dataArray![indexPath.row] as! NSDictionary)["title"] as! String)
    Cell.contentView.addSubview(titleL)
    
    // 售價(jià)
    let priceL = UILabel.init(frame: CGRect.init(x: 5, y: titleL.frame.maxY - 5, width: Cell.bounds.width - 10, height: 30))
    priceL.textColor = UIColor.red
    priceL.font = UIFont.boldSystemFont(ofSize: 17)
    priceL.text = String.init(format: "售價(jià):¥ %@", (dataArray![indexPath.row] as! NSDictionary)["price"] as! String)
    Cell.contentView.addSubview(priceL)
    
    return Cell
}
// TODO: 選擇哪個(gè)Cell
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    
}

3、 數(shù)據(jù)加載

// MARK: 獲取數(shù)據(jù)
func loadData() -> Void {
    let path = Bundle.main.path(forResource: "data", ofType: "plist")
    dataArray = NSArray.init(contentsOfFile: path!)
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容