在我的自定义 collectionView 布局中未调用 prepare()
Posted
技术标签:
【中文标题】在我的自定义 collectionView 布局中未调用 prepare()【英文标题】:prepare() not called in my custom collectionView layout 【发布时间】:2018-12-13 17:59:26 【问题描述】:我正在尝试设置自定义 collectionView 布局,感觉可能缺少步骤。
我创建了 collectionView,定义了约束,将布局从流更改为自定义,并选择了我的自定义类。
现在它不工作并且什么都没有显示,所以我正在尝试调试类方法,但我无法让任何打印语句工作,因为似乎没有调用任何函数。我在设置时缺少什么步骤?这是课程:
import UIKit
class CustomCollectionViewLayout: UICollectionViewLayout
private var cache = [IndexPath: UICollectionViewLayoutAttributes]()
private var contentWidth = CGFloat()
private var visibleLayoutAttributes = [UICollectionViewLayoutAttributes]()
private var oldBounds = CGRect.zero
private var collectionViewStartY: CGFloat
guard let collectionView = collectionView else
return 0
return collectionView.bounds.minY
private var collectionViewHeight: CGFloat
return collectionView!.frame.height
override public var collectionViewContentSize: CGSize
return CGSize(width: contentWidth, height: collectionViewHeight)
override public func prepare()
print("calling prepare") //This is what's not printing
guard let collectionView = collectionView,
cache.isEmpty else
return
updateInsets()
collectionView.decelerationRate = .fast
cache.removeAll(keepingCapacity: true)
cache = [IndexPath: UICollectionViewLayoutAttributes]()
oldBounds = collectionView.bounds
var xOffset: CGFloat = 0
var cellWidth: CGFloat = 5
for item in 0 ..< collectionView.numberOfItems(inSection: 0)
let cellIndexPath = IndexPath(item: item, section: 0)
let cellattributes = UICollectionViewLayoutAttributes(forCellWith: cellIndexPath)
cellattributes.frame = CGRect(x: xOffset, y: 0, width: cellWidth, height: collectionViewHeight)
xOffset = xOffset + cellWidth
contentWidth = max(contentWidth,xOffset)
cache[cellIndexPath] = cellattributes
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]?
visibleLayoutAttributes.removeAll(keepingCapacity: true)
print("layoutattributes called")
for (_, attributes) in cache
visibleLayoutAttributes.append(self.shiftedAttributes(from: attributes))
return visibleLayoutAttributes
override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes?
guard let attributes = cache[indexPath] else fatalError("No attributes cached")
print("layoutattributes called")
return shiftedAttributes(from: attributes)
override public func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool
if oldBounds.size != newBounds.size
cache.removeAll(keepingCapacity: true)
return true
override func invalidateLayout(with context: UICollectionViewLayoutInvalidationContext)
if context.invalidateDataSourceCounts cache.removeAll(keepingCapacity: true)
super.invalidateLayout(with: context)
extension CustomCollectionViewLayout
func updateInsets()
guard let collectionView = collectionView else return
collectionView.contentInset.left = (collectionView.bounds.size.width - 2.5) / 2
collectionView.contentInset.right = (collectionView.bounds.size.width - 2.5) / 2
override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint
guard let collectionView = collectionView else return super.targetContentOffset(forProposedContentOffset: proposedContentOffset)
let midX: CGFloat = collectionView.bounds.size.width / 2
guard let closestAttribute = findClosestAttributes(toXPosition: proposedContentOffset.x + midX) else return super.targetContentOffset(forProposedContentOffset: proposedContentOffset)
return CGPoint(x: closestAttribute.center.x - midX, y: proposedContentOffset.y)
private func findClosestAttributes(toXPosition xPosition: CGFloat) -> UICollectionViewLayoutAttributes?
guard let collectionView = collectionView else return nil
let searchRect = CGRect(
x: xPosition - collectionView.bounds.width, y: collectionView.bounds.minY,
width: collectionView.bounds.width * 2, height: collectionView.bounds.height
)
let closestAttributes = layoutAttributesForElements(in: searchRect)?.min(by: abs($0.center.x - xPosition) < abs($1.center.x - xPosition) )
return closestAttributes
private var continuousFocusedIndex: CGFloat
guard let collectionView = collectionView else return 0
let offset = collectionView.bounds.width / 2 + collectionView.contentOffset.x - 2.5 / 2
return offset / 2.5
private func shiftedAttributes(from attributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes
guard let attributes = attributes.copy() as? UICollectionViewLayoutAttributes else fatalError("Couldn't copy attributes")
let roundedFocusedIndex = round(continuousFocusedIndex)
let focusedItemWidth = CGFloat(20)
if attributes.indexPath.item == Int(roundedFocusedIndex)
attributes.transform = CGAffineTransform(scaleX: 10, y: 1)
else
let translationDirection: CGFloat = attributes.indexPath.item < Int(roundedFocusedIndex) ? -1 : 1
attributes.transform = CGAffineTransform(translationX: translationDirection * 20, y: 0)
return attributes
如果类以某种方式无效,是否会阻止调用其方法?在布局上自动执行 prepare() 方法是什么?
这是使用它的视图控制器:
class ViewController: UIViewController, UICollectionViewDelegate,UICollectionViewDataSource
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
return 10
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
let cell = customCollectionView.dequeueReusableCell(withReuseIdentifier: "singleCell", for: indexPath)
cell.backgroundColor = UIColor.random()
return cell
@IBOutlet weak var customCollectionView: UICollectionView!
override func viewDidLoad()
super.viewDidLoad()
customCollectionView.delegate = self
【问题讨论】:
为什么不设置数据源委托?还有你在哪里重新加载 collectionView 数据? 【参考方案1】:您应该提供集合视图的部分数量。否则,假定为 0,因此布局的实现不会开始。
func numberOfSections(in collectionView: UICollectionView) -> Int
return 1
同时尝试在视图控制器中调试 collectionView 和 collectionViewLayout 的值
【讨论】:
这并在 viewDidLoad 中将 dataSource 设置为 self 修复了它。谢谢!以上是关于在我的自定义 collectionView 布局中未调用 prepare()的主要内容,如果未能解决你的问题,请参考以下文章
详细分享UICollectionView的自定义布局(瀑布流, 线性, 圆形...)