UICollectionView:如何轻松处理更新

使用CollectionViews或TableViews时,困难的部分是需要添加,删除,移动某些单元格或更新其内容时。

使用装饰视图时甚至更多。

介绍

查看以下两个数组:

  let old = [“ A”,“ B”] 
let new = [“ B”,“ C”]

这些数组之间的差异非常容易计算:

  Deleted:[0] //旧数组中的索引 
已移动:[(从:1,至:0)]
插入的:[1] //在新数组中的索引
重新加载:[]

要计算此差异,我们使用一个比较两个数组,在这种情况下,这是数组中的值。 使用key,我们可以计算movedeleteinserts

  • 删除了位置0的键A
  • 钥匙B从位置1移到位置0
  • 键C插入位置1

当我们要计算两个数组之间的重载索引时,它变得更加复杂。 我们还需要一个key和一个值。 如果更改,我们需要重新加载该项目。

  let old = [(键:“ A”,值:0),(键:“ B”,值:0)] 
let new = [(键:“ C”,值:0),(键:“ B”,值:1)]

差异的结果:

 已删除:[0] //键A已删除 
感动:[]
插入:[0] //插入键C
重新加载:[1] // B的值已更改

完美,我们现在可以按IndexPath索引交换Int索引:

 让旧= [ 
(键:“ A”,值:0,索引:(部分:0,项目:0),
(键:“ B”,值:0,索引:(节:0,项目:1))
]
让新= [
(键:“ C”,值:0,索引:(部分:0,项目:0)),
(键:“ B”,值:1,索引:(第0节,项目:1))
(键:“ D”,值:0,索引:(部分:0,项目:2))
]
  //差异 
删除:[(section:0,item:0)] //删除键A
感动:[]
插入:[[section:0,item:0),(section:0,item:2)] //按键C和D
reloaded:[(section:0,item:1)] // B的值已更改

这样,我们可以轻松地计算twos collectionView dataSources之间的差异!

让我们从一个小示例开始:一个使用自定义布局构建的实时“高音”应用程序。 该应用程序每隔2秒就会收到一个新的供稿,并更新其collectionView。 每个“ tweet”由一个部分,一个用于内容的单元格,一个用于转发数的单元格和一个用于收藏夹计数的单元格表示。 仅当转推和收藏夹的计数为正时,才会显示它们。

在构建collectionView时,我使用的是Collor ,一种用于简化collectionView实现的微体系结构。

在上一篇文章中有更多信息 我建议在继续阅读之前先阅读它。

有一个collectionView的collectionData,一个可读文件,描述了collectionView,它是collectionView的模型:

Collor中 ,要计算插入和删除,您只需要向描述符添加唯一键,并以uid()方法表示即可:

  // 部分 
TweetSectionDescriptor()。 uid(tweet.id)
//项目
TweetDescriptor(适配器:TweetAdapter(tweet:tweet))。 uid(“文本”)
  TweetInfoDescriptor(适配器:RetweetAdapter(tweet:tweet))。  uid(“ retweet”) 
  TweetInfoDescriptor(适配器:FavoriteAdapter(tweet:tweet))。  uid(“收藏夹”) 

但是,对于计算重载, Collor需要更多信息,它需要知道描述符的“值”。 此值为适配器。 但是在Collor中 ,出于许多原因, CollectionAdapter协议不符合Equatable。 因此,如果要计算重载,则必须使您的适配器符合Diffable 。 如果您不这样做,则由于某些良好的原因,您可以将键用作值,该单元也将被删除然后重新插入:

  TweetDescriptor(适配器:TweetAdapter(tweet:tweet)) 
uid(“ text _ \(tweet.text)”)

重新加载的动画不同于删除/插入:

在我们的示例中,我们决定计算重载,因此通过实现isEqual(to other: Diffable?) -> Bool方法,使适配器符合Diffable

在差异计算过程中,如果键和索引相等,则Collor将测试值是否更改。 如果是,则将重新加载该物品。

自定义布局

如果您在自定义布局中使用装饰视图,您已经注意到编码实际上是多余的。 此外,您还必须处理collectionView更新并手动删除或插入装饰视图。

通过使用DecorationViewHandler功能, 科洛尔可能会为您提供帮助。

DecorationViewHandler允许您执行以下操作:

  • 注册视图类或XIB
  • 缓存然后返回修饰UICollectionViewLayoutAttributes
  • 在rect中返回属性
  • 管理收藏查看更新❤️

DecorationViewsHandler减少了代码和错误的行数,并为您管理更新! 根据updateItems它确定要删除或插入哪些装饰视图。

UICollectionView正在将视图重用于内存优化。 这就是为什么动画有时看起来很奇怪的原因:UICollectionView而不是创建新的背景视图(人类会做的事情),而是重用了另一个背景视图并将其从原来的位置移动到新位置。 您可以通过重写以下方法来改善此行为:
initialLayoutAttributesForAppearingDecorationElement(ofKind:at:)
finalLayoutAttributesForDisappearingDecorationElement(ofKind:at:)

结论

通过使用Collor构建您的collectionView,您不再需要在单元级别或装饰视图级别手动实现更新。 无需重新加载整个collectionView并丢失用户,您就可以向用户显示应用程序中正在发生的变化!

看看github上的实时示例。

感谢您的阅读,并让我知道您在Twitter上的想法。

航行sncf技术/ Collor
Collor – UICollectionView的面向MVVM数据的框架,具有强大而实用的功能。 github.com