我最终自己找到了问题的答案,而且我能够在不使用大量内部滚动视图的情况下完成它。这就是我的做法。由于我已经有了我的网格系统,所以我必须向我的集合视图添加一个额外的部分。这个部分的项目数量取决于我的事件数据源数组,如下所示:
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if section == Constants.numberOfSections {
//custom event section
return events.count
}
//calender grid items
return Constants.numberOfColumns
}
然而,我为集合视图定制的布局需要更新单元格属性。如果我没有告诉它有一个新单元格添加进来,那么它要么会崩溃,因为找不到相应的网格成员,要么会将该单元格添加到网格中,就像它是网格的另一部分。因此,我必须在自定义布局类中更新单元格属性,然后手动计算单元格应该在布局中放置的位置。所以,基本上每次我添加一个事件单元格时,布局都要手动计算该单元格在网格中的位置。这是我在自定义布局子类中手动计算事件坐标的函数(相关部分在自定义事件注释中):
fileprivate func setCellAttributes(item: Int, section: Int) {
// Build the UICollectionVieLayoutAttributes for the cell.
let cellIndex = IndexPath(item: item, section: section)
var cellWidth: Double = CELL_WIDTH
var cellHeight: Double = CELL_HEIGHT
var xPos: Double = 0
var yPos = Double(section) * CELL_HEIGHT
if section == collectionView!.numberOfSections - 1 {
//custom event items
let rect = getCustomEventRect(item: item)
xPos = Double(rect.x)
yPos = Double(rect.y)
cellHeight = Double(rect.height)
cellWidth = Double(rect.width)
} else if item == 0 {
//the y axis cells
cellWidth = yAxisCellWidth
} else {
//all other cells
xPos = calculateXPos(item: item)
}
let cellAttributes = UICollectionViewLayoutAttributes(forCellWith: cellIndex)
cellAttributes.frame = CGRect(x: xPos, y: yPos, width: cellWidth, height: cellHeight)
// Determine zIndex based on cell type.
if section == 0 && item == 0 {
//top left corner cell
cellAttributes.zIndex = 5
} else if section == 0 {
//y axis cells
cellAttributes.zIndex = 4
} else if section == collectionView!.numberOfSections - 1 {
//custom event cells
cellAttributes.zIndex = 2
} else if item == 0 {
//top x axis cells
cellAttributes.zIndex = 3
} else {
//all background schedule cells
cellAttributes.zIndex = 1
}
// Save the attributes.
cellAttrsDictionary[cellIndex] = cellAttributes
}
此外,每次我在viewController中更新事件时,都需要更新我的布局中的事件。因此,我在我的viewController中实现了以下内容:
var events: [CustomEvent] = [] {
didSet {
if let layout = theCollectionView.collectionViewLayout as? ScheduleCollectionViewLayout {
layout.events = events
}
}
}
当用户点击添加新事件时,我会相应地更新布局:
func removeEventCell(at indexPath: IndexPath) {
let eventSection: Int = collectionView!.numberOfSections - 1
let totalEventItems: Int = collectionView!.numberOfItems(inSection: eventSection)
//decrementing all indexPaths above the deleted event cell, so the attribute dictionary will be up to date, when reloadSections is run by the collectionView.
for item in 0..<totalEventItems where item > indexPath.item {
let targetIndexPath = IndexPath(item: item - 1, section: eventSection)
let cellAttr = cellAttrsDictionary[IndexPath(item: item, section: eventSection)]
cellAttr?.indexPath = targetIndexPath
cellAttrsDictionary[targetIndexPath] = cellAttr
}
let lastIndexPath = IndexPath(item: totalEventItems - 1, section: eventSection)
cellAttrsDictionary.removeValue(forKey: lastIndexPath)
}
fileprivate func addEventCellAttributes(numOfEventsToAdd: Int) {
for num in 1...numOfEventsToAdd {
setCellAttributes(item: events.count - num, section: collectionView!.numberOfSections - 1)
}
}