正如我在上面的标题中所说,当我调用dequeueReusableCell方法来创建collectionView的单元格时,我的应用程序崩溃了。当我注意到如果我改变numberOfItemsInSection返回参数时,我很惊讶应用程序不想崩溃! WTF!如果numberOfItemsInSection返回介于1和4之间的值,则应用程序可以正常工作,相反,如果numberOfItemsInSection返回大于5的值,则app将无效。 我正在使用自定义布局(UltraVisulaLayout),显然dequeueReusableCell ReuseIdentifier参数与故事板相同。 这是我的班级代码:
import UIKit
class CoriViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate
{
override func viewDidLoad()
{
super.viewDidLoad()
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
}
func numberOfSections(in collectionView: UICollectionView) -> Int
{
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
{
return 5
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
switch (indexPath.item! % 5)
{
case 0: cell.backgroundColor = UIColor.yellow()
case 1: cell.backgroundColor = UIColor.orange()
case 2: cell.backgroundColor = UIColor.red()
case 3: cell.backgroundColor = UIColor.green()
case 4: cell.backgroundColor = UIColor.blue()
default:
break
}
return cell
}
}
这里是UltraVisualLayout.swift代码:
import UIKit
/* The heights are declared as constants outside of the class so they can be easily referenced elsewhere */
struct UltravisualLayoutConstants
{
struct Cell
{
/* The height of the non-featured cell */
static let standardHeight: CGFloat = 100
/* The height of the first visible cell */
static let featuredHeight: CGFloat = 280
}
}
class UltravisualLayout: UICollectionViewLayout
{
// MARK: Properties and Variables
/* The amount the user needs to scroll before the featured cell changes */
let dragOffset: CGFloat = 180.0
var cache = [UICollectionViewLayoutAttributes]()
/* Returns the item index of the currently featured cell */
var featuredItemIndex: Int
{
get
{
/* Use max to make sure the featureItemIndex is never < 0 */
return max(0, Int(collectionView!.contentOffset.y / dragOffset))
}
}
/* Returns a value between 0 and 1 that represents how close the next cell is to becoming the featured cell */
var nextItemPercentageOffset: CGFloat
{
get
{
return (collectionView!.contentOffset.y / dragOffset) - CGFloat(featuredItemIndex)
}
}
/* Returns the width of the collection view */
var width: CGFloat
{
get
{
return collectionView!.bounds.width
}
}
/* Returns the height of the collection view */
var height: CGFloat
{
get
{
return collectionView!.bounds.height
}
}
/* Returns the number of items in the collection view */
var numberOfItems: Int
{
get
{
return collectionView!.numberOfItems(inSection: 0)
}
}
// MARK: UICollectionViewLayout
/* Return the size of all the content in the collection view */
override func collectionViewContentSize() -> CGSize
{
let contentHeight = (CGFloat(numberOfItems) * dragOffset) + (height - dragOffset)
return CGSize(width: width, height: contentHeight)
}
override func prepare() {
cache.removeAll(keepingCapacity: false)
let standardHeight = UltravisualLayoutConstants.Cell.standardHeight
let featuredHeight = UltravisualLayoutConstants.Cell.featuredHeight
var frame = CGRect.zero
var y: CGFloat = 0
for item in 0..<numberOfItems
{
let indexPath = IndexPath(item: item, section: 0)
let attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath)
/* Important because each cell has to slide over the top of the previous one */
attributes.zIndex = item
/* Initially set the height of the cell to the standard height */
var height = standardHeight
if (indexPath as NSIndexPath).item == featuredItemIndex
{
/* The featured cell */
let yOffset = standardHeight * nextItemPercentageOffset
y = collectionView!.contentOffset.y - yOffset
height = featuredHeight
} else if (indexPath as NSIndexPath).item == (featuredItemIndex + 1) && (indexPath as NSIndexPath).item != numberOfItems
{
/* The cell directly below the featured cell, which grows as the user scrolls */
let maxY = y + standardHeight
height = standardHeight + max((featuredHeight - standardHeight) * nextItemPercentageOffset, 0)
y = maxY - height
}
frame = CGRect(x: 0, y: y, width: width, height: height)
attributes.frame = frame
cache.append(attributes)
y = frame.maxY
}
}
/* Return all attributes in the cache whose frame intersects with the rect passed to the method */
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]?
{
var layoutAttributes = [UICollectionViewLayoutAttributes]()
for attributes in cache {
if attributes.frame.intersects(rect) {
layoutAttributes.append(attributes)
}
}
return layoutAttributes
}
/* Return the content offset of the nearest cell which achieves the nice snapping effect, similar to a paged UIScrollView */
override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint
{
let itemIndex = round(proposedContentOffset.y / dragOffset)
let yOffset = itemIndex * dragOffset
return CGPoint(x: 0, y: yOffset)
}
/* Return true so that the layout is continuously invalidated as the user scrolls */
override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool
{
return true
}
}