创建一个具有反向流布局的 UICollectionView

Tom*_*you 3 ios uicollectionview swift

我想创建一个类似于聊天视图的视图,其中最新消息出现在屏幕底部。我希望将UICollectionViewCells其“固定”到屏幕底部 - 与默认流程布局相反。我怎样才能做到这一点?

我从另一个 stackoverflow 答案中得到了这段代码,但它不适用于可变高度项目(它需要):

import Foundation
import UIKit

class InvertedStackLayout: UICollectionViewLayout {
    let cellHeight: CGFloat = 100 // Your cell height here...

    override func prepare() {
        super.prepare()
    }

    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        var layoutAttrs = [UICollectionViewLayoutAttributes]()

        if let collectionView = self.collectionView {
            for section in 0 ..< collectionView.numberOfSections {
                if let numberOfSectionItems = numberOfItemsInSection(section) {
                    for item in 0 ..< numberOfSectionItems {
                        let indexPath = IndexPath(item: item, section: section)
                        let layoutAttr = layoutAttributesForItem(at: indexPath)

                        if let layoutAttr = layoutAttr, layoutAttr.frame.intersects(rect) {
                            layoutAttrs.append(layoutAttr)
                        }
                    }
                }
            }
        }

        return layoutAttrs
    }

    override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
        let layoutAttr = UICollectionViewLayoutAttributes(forCellWith: indexPath)
        let contentSize = self.collectionViewContentSize

        layoutAttr.frame = CGRect(
            x: 0, y: contentSize.height - CGFloat(indexPath.item + 1) * cellHeight,
            width: contentSize.width, height: cellHeight)

        return layoutAttr
    }

    func numberOfItemsInSection(_ section: Int) -> Int? {
        if let collectionView = self.collectionView,
            let numSectionItems = collectionView.dataSource?.collectionView(collectionView, numberOfItemsInSection: section)
        {
            return numSectionItems
        }

        return 0
    }

    override var collectionViewContentSize: CGSize {
        get {
            var height: CGFloat = 0
            var bounds: CGRect = .zero

            if let collectionView = self.collectionView {
                for section in 0 ..< collectionView.numberOfSections {
                    if let numItems = numberOfItemsInSection(section) {
                        height += CGFloat(numItems) * cellHeight
                    }
                }

                bounds = collectionView.bounds
            }

            return CGSize(width: bounds.width, height: max(height, bounds.height))
        }
    }

    override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
        if let oldBounds = self.collectionView?.bounds,
            oldBounds.width != newBounds.width || oldBounds.height != newBounds.height
        {
            return true
        }

        return false
    }
}
Run Code Online (Sandbox Code Playgroud)

pin*_*nch 7

使用 CGAffineTransform 翻转您的 collectionView,使其从底部开始。

collectionView.transform = CGAffineTransform(scaleX: 1, y: -1)
Run Code Online (Sandbox Code Playgroud)

现在唯一的问题是您的所有单元格都上下颠倒显示。然后将变换应用到每个单元格以将其翻转回直立状态。

class InvertedCollectionViewFlowLayout: UICollectionViewFlowLayout {

    // inverting the transform in the layout, rather than directly on the cell, 
    // is the only way I've found to prevent cells from flipping during animated
    // cell updates

    override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
        let attrs = super.layoutAttributesForItem(at: indexPath)
        attrs?.transform = CGAffineTransform(scaleX: 1, y: -1)
        return attrs
    }

    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        let attrsList = super.layoutAttributesForElements(in: rect)
        if let list = attrsList {
            for i in 0..<list.count {
                list[i].transform = CGAffineTransform(scaleX: 1, y: -1)
            }
        }
        return attrsList
    }
}
Run Code Online (Sandbox Code Playgroud)