对 UICollectionViewLayout 使用无效上下文 [英] Using Invalidation Contexts for UICollectionViewLayout

查看:17
本文介绍了对 UICollectionViewLayout 使用无效上下文的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

因此,我通过从 shouldInvalidateLayoutForBoundsChange: 返回 YES 部分地在 UICollectionView 中实现了有效的粘性标头.但是,这会影响性能,我不想让整个布局失效,只想让我的标题部分失效.

So I have implemented working sticky headers in my UICollectionView in part by returning YES from shouldInvalidateLayoutForBoundsChange:. However, this impacts performance and I do not want to invalidate the entire layout, only my header section.

现在,根据官方文档,我可以使用 UICollectionViewLayoutInvalidationContext 为我的布局定义自定义失效上下文,但是文档非常缺乏.它要求我定义代表可以独立重新计算的布局数据部分的自定义属性",但我不明白这是什么意思.

Now, according to the official documentation I can use UICollectionViewLayoutInvalidationContext to define a custom invalidation context for my layout, but the documentation is very lacking. It asks me to "define custom properties that represent the parts of your layout data that can be recomputed independently", but I don't understand what they mean by this.

有没有人有过继承 UICollectionViewLayoutInvalidationContext 的经验?

Has anyone got any experience subclassing UICollectionViewLayoutInvalidationContext?

推荐答案

这是为 iOS8 准备的

我做了一些试验,我想我找到了使用失效布局的简洁方法,至少在 Apple 稍微扩展一下文档之前.

I experimented a bit and I think I figured out the clean way to use the invalidation layout, at least until Apple expands on the documentation a bit.

我试图解决的问题是在集合视图中获得粘性标题.我使用 FlowLayout 的子类和覆盖 layoutAttributesForElementsInRect: 的工作代码:(你可以在谷歌上找到工作示例).这要求我始终从 shouldInvalidateLayoutForBoundsChange: 返回 true:这是 Apple 希望我们通过上下文失效避免的主要性能提升.

The problem I was trying to solve was getting sticky headers in the collection view. I had working code for this using the subclass of FlowLayout and overriding layoutAttributesForElementsInRect: (you can find working examples on google). This required me to always return true from shouldInvalidateLayoutForBoundsChange: which is the supposed major performance kick in the nuts that Apple wants us to avoid with contextual invalidation.

干净的上下文失效

您只需要子类化 UICollectionViewFlowLayout.我不需要 UICollectionViewLayoutInvalidationContext 的子类,但这可能是一个非常简单的用例.

You only need to subclass the UICollectionViewFlowLayout. I didn't need a subclass for UICollectionViewLayoutInvalidationContext, but then this might be a pretty straightforward use case.

随着集合视图的滚动,流布局将开始接收 shouldInvalidateLayoutForBoundsChange: 调用.由于流布局已经可以处理这个问题,我们将在函数末尾返回超类的答案.通过简单的滚动,这将是错误的,并且不会重新布局元素.但是我们需要重新布局标题并让它们保持在屏幕顶部,因此我们将告诉集合视图仅使我们将提供的上下文无效:

As the collection view scrolls, the flow layout will start receiving shouldInvalidateLayoutForBoundsChange: calls. Since flow layout can already handle this, we'll return the superclass' answer at the end of the function. With simple scrolling this will be false, and will not re-layout the elements. But we need to re-layout the headers and have them stay at the top of the screen, so we'll tell the collection view to invalidate only the context that we'll provide:

override func shouldInvalidateLayoutForBoundsChange(newBounds: CGRect) -> Bool {
    invalidateLayoutWithContext(invalidationContextForBoundsChange(newBounds))
    return super.shouldInvalidateLayoutForBoundsChange(newBounds)
}

这意味着我们也需要重写 invalidationContextForBoundsChange: 函数.由于这个函数的内部工作是未知的,我们只需向超类询问失效上下文对象,确定我们想要使哪些集合视图元素失效,并将这些元素添加到失效上下文中.我把一些代码拿出来专注于这里的要点:

This means we need to override the invalidationContextForBoundsChange: function too. Since the internal workings of this function are unknown, we'll just ask the superclass for the invalidation context object, determine which collection view elements we want to invalidate, and add those elements to the invalidation context. I took some of the code out to focus on the essentials here:

override func invalidationContextForBoundsChange(newBounds: CGRect) -> UICollectionViewLayoutInvalidationContext! {

    var context = super.invalidationContextForBoundsChange(newBounds)

    if /... we find a header in newBounds that needs to be invalidated .../ {

            context.invalidateSupplementaryElementsOfKind(UICollectionElementKindSectionHeader, atIndexPaths:[NSIndexPath(forItem: 0, inSection:headerIndexPath.section)] )
    }
    return context
}

就是这样.标头和标头都无效.流布局将只接收一次对 layoutAttributesForSupplementaryViewOfKind: 的调用,其中 indexPath 在失效上下文中.如果您需要使单元格或装饰器失效,UICollectionViewLayoutInvalidationContext 上还有其他 invalidate* 函数.

That's it. The header and nothing but the header is invalidated. The flow layout will receive only one call to layoutAttributesForSupplementaryViewOfKind: with the indexPath in the invalidation context. If you needed to invalidate cells or decorators, there are other invalidate* functions on the UICollectionViewLayoutInvalidationContext.

最难的部分实际上是在 invalidationContextForBoundsChange: 函数中确定标头的 indexPaths.我的页眉和单元格都是动态调整大小的,仅查看边界 CGRect 就需要一些杂技才能使其工作,因为最明显有用的函数 indexPathForItemAtPoint: 如果该点位于页眉、页脚、装饰器或行间距.

The hardest part really is determining the indexPaths of the headers in the invalidationContextForBoundsChange: function. Both my headers and cells are dynamically sized and it took some acrobatics to get it to work from just looking at the bounds CGRect, since the most obviously helpful function, indexPathForItemAtPoint:, returns nothing if the point is on a header, footer, decorator or row spacing.

至于性能,我没有进行全面测量,但在滚动时快速浏览一下 Time Profiler 表明它在做正确的事情(右侧较小的尖峰是在滚动时).

As for the performance, I didn't do a full measurement, but a quick glance at Time Profiler while scrolling shows that it's doing something right (the smaller spike on the right is while scrolling).

这篇关于对 UICollectionViewLayout 使用无效上下文的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆