首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >创建一个具有反向流布局的UICollectionView

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

Stack Overflow用户
提问于 2017-11-29 21:25:43
回答 3查看 2.5K关注 0票数 4

我想要创建一个类似聊天视图的视图,其中最新的消息出现在屏幕底部。我希望UICollectionViewCells被“固定”在屏幕底部--与默认的流布局相反。我该怎么做?

我从另一个堆栈溢出回答中获得了这段代码,但它不适用于可变高度项(它需要这样做):

代码语言:javascript
运行
复制
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
    }
}
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2018-10-06 12:31:51

用一个collectionView翻转你的CGAffineTransform,使它从底部开始。

代码语言:javascript
运行
复制
collectionView.transform = CGAffineTransform(scaleX: 1, y: -1)

现在唯一的问题是你所有的细胞都是颠倒显示的。然后将转换应用到每个单元格上,将其垂直翻转回来。

代码语言:javascript
运行
复制
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
    }
}
票数 7
EN

Stack Overflow用户

发布于 2019-03-16 07:42:17

UICollectionView具有反向流量布局和动态单元格和标头高度。

代码语言:javascript
运行
复制
import Foundation
import UIKit

class InvertedFlowLayout: UICollectionViewFlowLayout {

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

    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        guard super.layoutAttributesForElements(in: rect) != nil else { return nil }
        var attributesArrayNew = [UICollectionViewLayoutAttributes]()

        if let collectionView = self.collectionView {
            for section in 0 ..< collectionView.numberOfSections {
                for item in 0 ..< collectionView.numberOfItems(inSection: section) {
                    let indexPathCurrent = IndexPath(item: item, section: section)
                    if let attributeCell = layoutAttributesForItem(at: indexPathCurrent) {
                        if attributeCell.frame.intersects(rect) {
                            attributesArrayNew.append(attributeCell)
                        }
                    }
                }
            }

            for section in 0 ..< collectionView.numberOfSections {
                let indexPathCurrent = IndexPath(item: 0, section: section)
                if let attributeKind = layoutAttributesForSupplementaryView(ofKind: UICollectionView.elementKindSectionHeader, at: indexPathCurrent) {
                    attributesArrayNew.append(attributeKind)
                }
            }
        }

        return attributesArrayNew
    }

    override func layoutAttributesForSupplementaryView(ofKind elementKind: String, at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
        let attributeKind = UICollectionViewLayoutAttributes(forSupplementaryViewOfKind: elementKind, with: indexPath)

        if let collectionView = self.collectionView {
            var fullHeight: CGFloat = 0.0

            for section in 0 ..< indexPath.section + 1 {
                for item in 0 ..< collectionView.numberOfItems(inSection: section) {
                    let indexPathCurrent = IndexPath(item: item, section: section)
                    fullHeight += cellHeight(indexPathCurrent) + minimumLineSpacing
                }
            }

            attributeKind.frame = CGRect(x: 0, y: collectionViewContentSize.height - fullHeight - CGFloat(indexPath.section + 1) * headerHeight(indexPath.section) - sectionInset.bottom + minimumLineSpacing/2, width: collectionViewContentSize.width, height: headerHeight(indexPath.section))
        }

        return attributeKind
    }

    override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
        let attributeCell = UICollectionViewLayoutAttributes(forCellWith: indexPath)

        if let collectionView = self.collectionView {
            var fullHeight: CGFloat = 0.0

            for section in 0 ..< indexPath.section + 1 {
                for item in 0 ..< collectionView.numberOfItems(inSection: section) {
                    let indexPathCurrent = IndexPath(item: item, section: section)
                    fullHeight += cellHeight(indexPathCurrent) + minimumLineSpacing

                    if section == indexPath.section && item == indexPath.item {
                        break
                    }
                }
            }

            attributeCell.frame = CGRect(x: 0, y: collectionViewContentSize.height - fullHeight + minimumLineSpacing - CGFloat(indexPath.section) * headerHeight(indexPath.section) - sectionInset.bottom, width: collectionViewContentSize.width, height: cellHeight(indexPath) )
        }

        return attributeCell
    }

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

            if let collectionView = self.collectionView {
                for section in 0 ..< collectionView.numberOfSections {
                    for item in 0 ..< collectionView.numberOfItems(inSection: section) {
                        let indexPathCurrent = IndexPath(item: item, section: section)
                        height += cellHeight(indexPathCurrent) + minimumLineSpacing
                    }
                }

                height += sectionInset.bottom + CGFloat(collectionView.numberOfSections) * headerHeight(0)
                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
    }

    func cellHeight(_ indexPath: IndexPath) -> CGFloat {
        if let collectionView = self.collectionView, let delegateFlowLayout = collectionView.delegate as? UICollectionViewDelegateFlowLayout {
            let size = delegateFlowLayout.collectionView!(collectionView, layout: self, sizeForItemAt: indexPath)
            return size.height
        }

        return 0
    }

    func headerHeight(_ section: Int) -> CGFloat {
        if let collectionView = self.collectionView, let delegateFlowLayout = collectionView.delegate as? UICollectionViewDelegateFlowLayout {
            let size = delegateFlowLayout.collectionView!(collectionView, layout: self, referenceSizeForHeaderInSection: section)
            return size.height
        }

        return 0
    }
}
票数 1
EN

Stack Overflow用户

发布于 2017-11-30 06:51:16

您可以旋转(转换) collectionView 180度,因此顶部将在底部和旋转(转换)每个单元格180,使他们看起来正常。

票数 -2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47562091

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档