问题:
我希望有一个垂直和水平滚动的网格,并通过CoreData&{39}更新NSFetchedResultsController
解决方案1:流程布局中的嵌套集合视图
NSFetchedResultsController
。 解决方案2:实施自定义流程布局
NSFetchedResultsController
现在,2看起来要简单得多 - 但创建自定义集合视图布局不是我以前做过的事情,Apple的文档声明:
*" *在开始构建自定义布局之前,请考虑是否真的需要这样做。 UICollectionViewFlowLayout类提供 已经优化的大量行为 效率...."
所以我的问题是 - 是这种情况,自定义流程布局真的会让生活更轻松吗?如果是这样,有没有人得到一些Swift示例?我在Obj-C中看过一些,但在Swift中没有看到......
答案 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)
}
}
}