在集合视图中垂直和水平滚动 - 嵌入式流程布局与自定义布局

时间:2016-09-17 15:00:01

标签: ios swift layout collectionview

问题: 我希望有一个垂直和水平滚动的网格,并通过CoreData&{39}更新NSFetchedResultsController

解决方案1:流程布局中的嵌套集合视图

  • 首先使用流程布局和垂直滚动设置集合视图
  • 此集合视图的每个单元格本身流程布局中的水平滚动的集合视图。
  • 然后,我必须在每个子集合视图中附加NSFetchedResultsController

解决方案2:实施自定义流程布局

  • 在自定义布局中放置单个集合视图。
  • 使用单个NSFetchedResultsController

现在,2看起来要简单得多 - 但创建自定义集合视图布局不是我以前做过的事情,Apple的文档声明:

  

*" *在开始构建自定义布局之前,请考虑是否真的需要这样做。 UICollectionViewFlowLayout类提供   已经优化的大量行为   效率...."

所以我的问题是 - 这种情况,自定义流程布局真的会让生活更轻松吗?如果是这样,有没有人得到一些Swift示例?我在Obj-C中看过一些,但在Swift中没有看到......

1 个答案:

答案 0 :(得分:1)

这是我在Swift 2.3中的自定义CollectionViewLayout。您必须实现TwoWayCollectionViewLayoutDatasource才能使用它。

希望它可以帮到你。

protocol TwoWayCollectionViewLayoutDatasource: NSObjectProtocol {
    func twoWayCollectionViewLayout(layout: TwoWayCollectionViewLayout, colectionView: UICollectionView, widthForColumnIndex index: Int) -> CGFloat
    func twoWayCollectionViewLayout(layout: TwoWayCollectionViewLayout, colectionView: UICollectionView, heighForRowIndex index: Int) -> CGFloat
    func twoWayCollectionViewLayoutNumberOfFixColumns(layout: TwoWayCollectionViewLayout, colectionView: UICollectionView) -> Int
    func twoWayCollectionViewLayoutNumberOfFixRows(layout: TwoWayCollectionViewLayout, colectionView: UICollectionView) -> Int
}

class TwoWayCollectionViewLayout: UICollectionViewLayout {
    private var itemAttributes : [[UICollectionViewLayoutAttributes]] = []
    private var itemsSize : [[CGSize]] = []
    private var contentSize : CGSize = CGSizeZero

    weak var dataSource: TwoWayCollectionViewLayoutDatasource!

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

    override func prepareLayout() {
        if self.collectionView?.numberOfSections() == 0 {
            return
        }

        let numberOfColumns = self.collectionView!.numberOfItemsInSection(0)
        let numberOfRows = self.collectionView!.numberOfSections()
        let numberOfFixColumns = self.dataSource.twoWayCollectionViewLayoutNumberOfFixColumns(self, colectionView: self.collectionView!)
        let numberOfFixRows = self.dataSource.twoWayCollectionViewLayoutNumberOfFixRows(self, colectionView: self.collectionView!)

        if self.itemAttributes.count > 0 {
            for var rowIndex = 0; rowIndex < numberOfRows; rowIndex++ {
                for var columnIndex = 0; columnIndex < numberOfColumns; columnIndex++ {
                    if rowIndex < numberOfFixRows || columnIndex < numberOfFixColumns {
                        if let attributes = self.layoutAttributesForItemAtIndexPath(NSIndexPath(forItem: columnIndex, inSection: rowIndex)) {
                            var frame = attributes.frame
                            if rowIndex < numberOfFixRows {
                                var yPosition = self.collectionView!.contentOffset.y
                                for var i = 0; i < rowIndex; i++ {
                                    yPosition += self.itemsSize[i][columnIndex].height
                                }
                                frame.origin.y = yPosition
                            }
                            if columnIndex < numberOfFixColumns {
                                var xPosition = self.collectionView!.contentOffset.x
                                for var i = 0; i < columnIndex; i++ {
                                    xPosition += self.itemsSize[rowIndex][i].width
                                }
                                frame.origin.x = xPosition
                            }

                            attributes.frame = frame
                        }
                    }
                }
            }
        } else {
            if (self.itemsSize.count == 0) {
                self.calculateItemsSize()
            }

            var xOffset : CGFloat = 0
            var yOffset : CGFloat = 0
            var contentWidth : CGFloat = 0
            var contentHeight : CGFloat = 0

            for var rowIndex = 0; rowIndex < numberOfRows; rowIndex++ {
                var rowAttributes: [UICollectionViewLayoutAttributes] = []
                for var columnIndex = 0; columnIndex < numberOfColumns; columnIndex++ {
                    let itemSize = self.itemsSize[rowIndex][columnIndex]
                    let attributes = UICollectionViewLayoutAttributes(forCellWithIndexPath: NSIndexPath(forItem: columnIndex, inSection: rowIndex))
                    attributes.frame = CGRectIntegral(CGRectMake(xOffset, yOffset, itemSize.width, itemSize.height))

                    if columnIndex < numberOfFixColumns && rowIndex < numberOfFixRows {
                        attributes.zIndex = 1024;
                    } else  if columnIndex < numberOfFixColumns || rowIndex < numberOfFixRows {
                        attributes.zIndex = 1023
                    } else {
                        attributes.zIndex = 1000
                    }

                    if columnIndex == 0 {
                        var frame = attributes.frame
                        frame.origin.x = self.collectionView!.contentOffset.x
                        attributes.frame = frame
                    }

                    if rowIndex == 0 {
                        var frame = attributes.frame
                        frame.origin.y = self.collectionView!.contentOffset.y
                        attributes.frame = frame
                    }

                    rowAttributes.append(attributes)

                    xOffset += itemSize.width

                    if columnIndex == numberOfColumns - 1 {
                        if xOffset > contentWidth {
                            contentWidth = xOffset
                        }
                        xOffset = 0
                        yOffset += itemSize.height
                    }
                }

                self.itemAttributes.append(rowAttributes)
            }

            if let attributes = self.itemAttributes.last?.last as UICollectionViewLayoutAttributes? {
                contentHeight = attributes.frame.origin.y + attributes.frame.size.height
                self.contentSize = CGSizeMake(contentWidth, contentHeight)
            }
        }
    }

    override func collectionViewContentSize() -> CGSize {
        return self.contentSize
    }

    override func layoutAttributesForItemAtIndexPath(indexPath: NSIndexPath) -> UICollectionViewLayoutAttributes? {
        if self.itemAttributes.count > indexPath.section {
            if self.itemAttributes[indexPath.section].count > indexPath.item {
                return self.itemAttributes[indexPath.section][indexPath.item]
            } else {
                print("Dont match row \(indexPath)")
            }
        } else {
            print("Dont match section \(indexPath)")
        }
        return nil
    }

    override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        var attributes = [UICollectionViewLayoutAttributes]()
        for section in self.itemAttributes {
            let filteredArray = section.filter({ (item) -> Bool in
                return CGRectIntersectsRect(rect, item.frame)
            })

            attributes.appendContentsOf(filteredArray)
        }
        return attributes
    }

    override func shouldInvalidateLayoutForBoundsChange(newBounds: CGRect) -> Bool {
        return true
    }

    func calculateItemsSize() {
        let numberOfColumns = self.collectionView!.numberOfItemsInSection(0)
        let numberOfRows = self.collectionView!.numberOfSections()

        self.itemsSize.removeAll()
        for var rowIndex = 0; rowIndex < numberOfRows; rowIndex++ {
            var rowSize: [CGSize] = []
            for var columnIndex = 0; columnIndex < numberOfColumns; columnIndex++ {
                let w = self.dataSource.twoWayCollectionViewLayout(self, colectionView: self.collectionView!, widthForColumnIndex: columnIndex)
                let h = self.dataSource.twoWayCollectionViewLayout(self, colectionView: self.collectionView!, heighForRowIndex: rowIndex)
                rowSize.append(CGSizeMake(w, h))
            }

            self.itemsSize.append(rowSize)
        }
    }
}