目前,我有一个日历网格系统。我正在尝试实现一项功能,我可以在其中显示日历中的事件 block 。所以,我希望能够实现 用户可以通过点击单元格在网格系统中的任何位置添加“无标题” block 。我的第一个想法是在 UICollectionView 之外添加一个 View ,但是当我在日历上滚动时。 “无标题” block 仍然存在,并且仍然在屏幕上。我需要在集合布局中添加一个单元格,以使其保持在 Collection View 的流程中。为了构建网格系统,我必须创建一个 UICollectionViewLayout 的自定义子类,因此我没有使用 UICollectionViewFlowLayout。我仍然对如何在另一个单元格上方添加一个单元格有些迷惑,关于实现此功能的最佳方法有什么想法吗?
最佳答案
我最终找到了我自己问题的答案。而且,我能够做到这一点,而不必用一堆内部 ScrollView 来破解 collectionView。这就是我所做的。我已经有了我的网格系统,所以我必须在我的 Collection View 中添加一个额外的部分。此部分的项目数取决于我的事件数据源数组:
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if section == Constants.numberOfSections {
//custom event section
return events.count
}
//calender grid items
return Constants.numberOfColumns
}
但是,我的 Collection View 的自定义布局需要更新有关 cellAttributes 的信息。如果我没有告诉它添加了一个新的单元格,那么它要么因为找不到相应的网格成员而崩溃,要么将单元格添加到网格中,就像它是网格的另一部分一样。因此,我必须更新自定义布局类中的 cellAttributes,然后手动计算单元格在布局中的放置位置。所以,基本上每次我添加一个事件单元格时,布局都必须手动计算该单元格在网格中的位置。这是我在自定义布局子类中手动计算事件坐标的函数(相关部分在自定义事件注释中):
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)
}
}
这是计算放置单元格的位置的一个非常手动的过程,但它使 collectionView 保持平稳工作,并允许在单元格上方放置单元格的功能。我的回答总结是,我为我的自定义事件添加了一个新部分,我必须手动计算这些单元格的位置,而不是让它们随网格系统流动。我的交互式日历现在可以完美运行了。如果您在尝试创建网格系统时遇到问题,我使用了本教程: https://www.credera.com/blog/mobile-applications-and-web/building-a-multi-directional-uicollectionview-in-swift/
关于ios - 在 Collection View 之上创建 View ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42545304/