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

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

问题描述

所以我已经在我的UICollectionView中实现了工作粘性头部分从 YES shouldInvalidateLayoutForBoundsChange:。然而,这影响性能,我不想使整个布局,只有我的标题部分无效。

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?

推荐答案

is for iOS8

我尝试了一下,我想我发现使用无效布局的干净的方法,至少直到苹果公司扩展文档

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:这是苹果希望我们避免与上下文无效的坚果中的主要性能。

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:调用。因为流布局可以处理这个,我们将在函数的结尾返回超类的答案。使用简单的滚动这将是false,并且不会重新布局元素。但是我们需要重新布局标题,并将它们保留在屏幕顶部,因此我们将告诉集合视图使我们将提供的上下文无效:

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:function中的头的indexPath 。我的标题和单元格是动态大小,它需要一些杂技,以使它从工作,只需查看边界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.

至于性能,我没有做一个完整的测量,但快速浏览时间分析器,同时滚动显示它做正确的事情右边的穗是滚动时)。

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天全站免登陆