iOS上的Messenger Messenger头像动画

介绍

当您的消息收件人看到您的消息时,Facebook Messenger具有特殊的可见状态动画。 它旨在向发件人提供信息通知,告知您的受众群体正在积极在线并实时查看您的消息。 此功能的商业价值不仅是鼓励人们发送更多实时消息,还使经常发送消息的人们感到高兴。 1:1聊天以及群聊中都可以使用此功能。 我创建了一个简短的gif,以说明所看到的头部移动动画:

那么我们从哪里开始呢?

#1 Vanilla UICollectionView

首先,我确定的一件事是,我们应该使用UICollectionView

UICollectionView不仅支持自定义布局,而且还具有用于插入/更新/删除/移动操作的本机动画。 因此,最重要的一点是移动动画。 从Apple文档获取UICollectionView:

func moveItem(at indexPath: IndexPath, 
to newIndexPath: IndexPath)

我们可以使用它来实现看到的脑袋之间的移动动画。 UICollectionView在内部管理所有动画详细信息,并通过配置正确的动画属性来处理所有繁重的工作,并将其发送给Core Animation以获得实际效果。

所以现在的问题是,我们如何为这个UICollectionView构造数据模型? 这很容易,我们只需要创建一个一维对象数组,其中包含一个Message或一个User (对于可见头)。

现在,我们有了三个节控制器,并且HScrollSeenHeadSectionController包含另一个H滚动UICollectionView用于显示的头部。 这次我不打算使用自定义UICollectionViewLayout,因为我认为嵌套的SectionController可以自动处理。 但是,这就是我得到的:

事实证明,使用嵌套部分控制器作为所有可见头部的容器存在一些问题:

  • 没有移动动画。 数据模型现在变为二维数组,我们必须模拟更新的数据结构。 IGListKit不会将其视为移动动画,因为从技术上讲,我们不能在两个不同的 UICollectionView之间移动单元格。
  • H滚动UICollectionView的布局不正确。 为了布局从右边缘开始对齐的可见头,我们必须为此H滚动组件专门实现一个新的自定义UICollectionViewLayout。

我放弃了这种方法,我认为需要在库级别解决此问题,以支持不同UICollectionView之间的单元格移动动画,这似乎并不简单。

#3 IGListKit +自定义UICollectionViewLayout

最后,我决定使用#1中的Custom UICollectionViewLayout并将其与IGListKit结合使用。 基本上,相同的想法是使用一维数组并使用单个UICollectionView为屏幕上的所有UI元素提供动力。

使用IGListKit的好处是,它全部是数据驱动的,无需了解有关何时移动或何时删除的UICollectionView详细信息。 图书馆会自动为我们计算它,我们可以这样做:

如果我们在第3行点击最右边的seeedHead,则需要对两个seehead进行动画处理,因此我们的插入和删除更新集为:

  1. 插入到[第3节,项目0]上 ,元素类型: seenhead1
  2. [第2节,项目0]上删除,元素类型: seenhead0
  3. 并且由于我们要移动的位置会影响到seehead0之后的所有seehead ,因此我们将需要为[section 2,item 0] (元素类型: seehead1)添加插入。
  4. 最后,对于initialLayoutAttributesForAppearingSupplementaryElementfinalLayoutAttributesForDisappearingSupplementaryElement ,我们可以将userId与具有当前布局属性的先前布局属性相关联,这样我们可以进行快速查找并轻松实现这两个API。

使用补充视图方法的要点是正确计算需要删除并插入哪个补充视图,否则将不会调用数据源API“ viewForSupplementaryElementOfKind”,这将使seeedHead保持不变。

随意查看补充视图方法的简单实施的源代码:链接

学习

当然,通过构建自己的自定义UIScrollView(可以控制动画或布局的所有粒度)来实现此动画的方法有很多。 但是我发现将UICollectionView与自定义布局一起使用是最简单的方法。

这个周末小项目还有许多其他有趣的技术细节:

  • 我们如何为看到的标题和消息生成生产质量代码的自定义UICollectionViewLayout的实现细节,因为挑战在于如何构建具有60fps滚动性能的有效布局。
  • 客户/服务器通信对于可见状态的挑战,尤其是在发生许多异步可见头部突变的群聊环境中。 大规模处理绝对是一个有趣的工程问题。

谢谢阅读! 让我知道您是否有任何问题,欢迎反馈!

lorixx / TestSeenheadWithIGListKit

TestSeenheadWithIGListKit – Messenger通过IGListKit看到头部移动

github.com

参考文献

  1. https://github.com/Instagram/IGListKit/
  2. https://www.objc.io/issues/1-view-controllers/lighter-view-controllers/
  3. https://medium.com/ios-os-x-development/ios-architecture-patterns-ecba4c38de52
  4. https://developer.apple.com/documentation/uikit/uicollectionview