我计划在我的集合视图的某个位置添加一个视图。因此,我想使用装饰视图。现在,该位置应每分钟更改一次。如何在 iOS 7 和 iOS 8 上使用 UICollectionView
实现这一目标?
似乎可以通过 invalidateLayoutWithContext
来实现这一目标,但是是否可以在一个布局中使用多个 UICollectionViewLayoutInvalidationContext
?
在阅读 文档
时要为您的布局定义自定义无效上下文,请子类化 UICollectionViewLayoutInvalidationContext 类。在子类中 定义自定义属性,这些属性代表布局数据中 可以独立重新计算的部分。当您需要在 时,创建一个无效上下文子类的实例,并根据自定义属性对其进行配置。 子类的实例,根据布局信息的变化配置自定义属性,然后将该对象传递给 信息发生变化时配置自定义属性,然后将该对象传递给布局的 invalidateLayoutWithContext: 方法传递该对象。该方法的自定义实现 方法的自定义实现可以使用无效上下文中的信息 只重新计算布局中发生变化的部分。target="_blank">more如果您为您的布局对象定义了一个自定义的无效上下文类 对象定义了自定义的无效上下文类,则还应覆盖 invalidationContextClass 方法,并返回自定义类。 并返回自定义类。当集合视图创建一个 类的实例。 上下文。从该方法返回自定义子类可确保 您的布局对象始终拥有它所期望的无效上下文。
似乎只能使用一个无效上下文,因为您不知道何时在 invalidationContextClass
中返回哪个上下文。
有时我需要使整个布局失效(例如更改方向),但我也需要仅更改装饰视图。
这可能吗?
here 、here 或 here 等其他问题并没有为我的情况提供完整的解决方案,或者仅适用于 iOS 8。
如果您有任何疑问,请与我们联系。
你当然可以在UICollectionView
中实现这个功能,并且你对invalidateLayoutWithContext:
和UICollectionViewLayoutInvalidationContext
的使用是正确的。你对只能使用一个无效上下文的担心是有道理的,但是我们可以通过巧妙地子类化UICollectionViewLayoutInvalidationContext
并利用其属性来解决这个问题。
以下是如何实现这一目标的步骤:
- 子类化
UICollectionViewLayoutInvalidationContext
:
class CustomLayoutInvalidationContext: UICollectionViewLayoutInvalidationContext {
var invalidateDecorationViewOnly: Bool = false
}
这个自定义上下文添加了一个布尔属性invalidateDecorationViewOnly
,我们用它来表明是否只应该更新装饰视图。
- 子类化
UICollectionViewLayout
:
class CustomCollectionViewLayout: UICollectionViewLayout {
// ... 你的布局逻辑 ...
override class var invalidationContextClass: AnyClass {
return CustomLayoutInvalidationContext.self
}
override func invalidateLayoutWithContext(context: UICollectionViewLayoutInvalidationContext) {
guard let customContext = context as? CustomLayoutInvalidationContext else {
super.invalidateLayoutWithContext(context)
return
}
if customContext.invalidateDecorationViewOnly {
// 只更新装饰视图
// 例如,调用 invalidateDecorationElementsOfKind:atIndexPaths:
} else {
// 更新整个布局
super.invalidateLayoutWithContext(context)
}
}
// ... 你的布局逻辑 ...
}
在这个自定义布局中:
- 我们重写了
invalidationContextClass
,返回CustomLayoutInvalidationContext
类。 - 我们重写了
invalidateLayoutWithContext:
,检查传入的上下文是否是CustomLayoutInvalidationContext
类型。 -
如果是,我们根据
invalidateDecorationViewOnly
属性决定是更新整个布局还是只更新装饰视图。 -
使用自定义布局和上下文:
// 在你的视图控制器中:
// 初始化你的自定义布局
let layout = CustomCollectionViewLayout()
// ... 配置你的布局 ...
// 初始化你的集合视图
let collectionView = UICollectionView(frame: CGRectZero, collectionViewLayout: layout)
// ... 配置你的集合视图 ...
// 当你需要只更新装饰视图时:
let context = layout.invalidationContext() as! CustomLayoutInvalidationContext
context.invalidateDecorationViewOnly = true
layout.invalidateLayoutWithContext(context)
// 当你需要更新整个布局时:
layout.invalidateLayout() // 或者使用没有 customContext 的 invalidateLayoutWithContext:
通过这种方式,你可以有效地控制布局的哪些部分需要更新,并在只更新装饰视图时提高性能。
其他技巧:
- 为了提高性能,请确保在你的布局计算中尽可能多地缓存信息。
- 使用 Instruments 中的 Time Profiler 来分析你的布局代码并识别任何性能瓶颈。
希望这些步骤能帮助你在 iOS 7 和 8 上使用UICollectionView
实现你想要的功能!