NSCollcectionViewLayout 的 prepareLayout 方法

prepareLayout method of NSCollcectionViewLayout

我很难理解 NSCollectionViewLayoutprepareLayout 方法的目的。

按照官方apple documentation是这样写的

During the layout process, the collection view calls several methods of your layout object to gather information. In particular, it calls three very important methods, whose implementations drive the core layout behavior.

  • Use the prepareLayout method to perform your initial layout calculations. These calculations provide the basis for everything the layout object does later.

  • Use the collectionViewContentSize method to return the smallest rectangle that completely encloses all of the elements in the collection view. Use the calculations from your prepareLayout method to specify this rectangle.

  • Use the layoutAttributesForElementsInRect: method to return the layout attributes for all elements in the specified rectangle. The collection view typically requests only the subset of visible elements, but may include elements that are just offscreen.

The prepareLayout method is your chance to perform the main calculations associated with the layout process. Use this method to generate an initial list of layout attributes for your content. For example, use this method to calculate the frame rectangles of all elements in the collection view. Performing all of these calculations up front and caching the resulting data is often simpler than trying to compute attributes for individual items later.

In addition to the layoutAttributesForElementsInRect: method, the collection view may call other methods to retrieve layout attributes for specific items. By performing your calculations in advance, your implementations of those methods should be able to return cached information without having to recompute that information first. The only time your layout object needs to recompute its layout information is when your app invalidates the layout. For example, you might invalidate the layout when the user inserts or deletes items.

所以我天真地以此为指导并重写了自定义布局的实现。我计算了 collectionViewContentSize 并预先计算了此方法中使用的数组

- (NSArray<__kindof NSCollectionViewLayoutAttributes *>*)layoutAttributesForElementsInRect:(NSRect)rect;

这样,在所有 3 个必需的方法中,我只是 return 缓存的值。在此之后,我的 collectionView 突然变得非常迟钝。

显然方法 prepareLayout 在每次滚动时都会被调用。

谁能解释一下这是什么意思。还是我什么都不懂?

所以这是我的错。显然如果

- (BOOL)shouldInvalidateLayoutForBoundsChange:(NSRect)newBounds;

returns 是的。然后调用此方法。我只是更改了此方法 returns NO 并且一直停止调用方法 prepareLayout

通常的做法是,如果您不想在每次出现滚动事件时都调用 prepare,可以保留一个 CGSize 实例 属性 并实现 shouldInvalidateLayout,以便它returns 仅当新边界大小与存储的 CGSize 属性 值不同时才为 YES。

这是一个 Swift 示例,但我相信您可以将其翻译成 Objective-C:

var oldBoundsSize = CGSize.zero
override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
    let ok = newBounds.size != self.oldBoundsSize
    if ok {
        self.oldBoundsSize = newBounds.size
    }
    return ok
}