在 layoutAttributesForElements 中更改帧会减慢动画速度

Posted

技术标签:

【中文标题】在 layoutAttributesForElements 中更改帧会减慢动画速度【英文标题】:Changing frames in layoutAttributesForElements slow down animation 【发布时间】:2018-01-03 14:47:58 【问题描述】:

我有一个自定义的 CollectionViewFlowLayout,我在其中覆盖了layoutAttributesForElements(in rect: CGRect),以便让元素按照设计规范进行定位。

一切都很好,但在某些情况下,要制作“选择模式”动画,我需要更新帧的 y 位置,但是当我这样做时,我的动画会有一点延迟。

如果我保持y位置,更新属性的x,宽高,动画就ok了。

为什么会这样?我该如何避免呢?

这是我的布局模型:

这是选择的模式:

基本上,我的动画包括更改可见单元格的变换,以使它们更小但居中,并保持对齐和正确的间距,我在 layoutAttributesForElements 中操作框架并使布局无效。

编辑:

其他解决方案(例如更改 cellSize 和 minimumInteritemSpacing 对我不起作用,因为用于 cellSize 更改的 UICollectionView 动画非常不稳定

【问题讨论】:

我不是你如何为这个布局更改设置动画,但我能够通过适当地更改项目大小并在动画块中调用 invalidateLayout() 来获得非常流畅的实现。看起来你做的工作比你需要做的要多。我在这里做了一个测试项目github.com/edmonston/test-cvlo 这是一个视频github.com/edmonston/test-cvlo/blob/master/demo.mov?raw=true 看起来不错,我试试这个 它有点工作,但它不能解决我原来的问题。您只能更改项目之间的间距,而不是屏幕边缘的间距。我修改了您的代码以设置 UICollectionView 的 contentInset,但现在我必须从 cellSize 中删除该 inset,否则会破坏布局。在您的示例中,计算很简单,但就我而言,当时我不知道每行有多少个单元格,因此我无法计算并返回正确的项目大小。这就是为什么我使用自定义 UICollectionViewFlowLayout 忘记我所说的几乎所有内容,我确实有每行的单元格数量,我对您的想法做了一些进一步的更改,但现在效果很好!我必须扔掉所有自定义 UICollectionViewFlowLayout 代码,谢谢! 请添加答案,以便我接受 【参考方案1】:

正如我在 cmets 中提到的,似乎有一个更简单的方法:我能够通过适当地更改从 collectionView(_:layout:sizeForItemAt:)collectionView(_:layout:minimumLineSpacingForSectionAt:)collectionView(_:minimumInteritemSpacingForSectionAt:) 返回的值来获得一个非常顺利的实现,并且在适当的时候在动画块内调用invalidateLayout()layoutIfNeeded()

一个非常基本的项目布局的返回值可能如下所示(separatorSize(isInSelectionMode:) 根据选择状态返回更大或更小的值):

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize 
    let totalRowHeight: CGFloat = 100
    let widthRatio: CGFloat
    switch indexPath.item % 4 
    case 0, 3: widthRatio = (2.0 / 3.0)
    case 1, 2: widthRatio = (1.0 / 3.0)
    default: widthRatio = 1.0
    
    return CGSize(width: (collectionView.bounds.width - separatorSize(isInSelectionMode: selectionMode).width) * widthRatio,
                  height: totalRowHeight - separatorSize(isInSelectionMode: selectionMode).height)


func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat 
    return separatorSize(isInSelectionMode: selectionMode).height


func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat 
    return separatorSize(isInSelectionMode: selectionMode).width

然后,您只需在动画块内切换selectionMode,同时使布局无效。

我做了一个demo project here 和一个demo video here。

【讨论】:

以上是关于在 layoutAttributesForElements 中更改帧会减慢动画速度的主要内容,如果未能解决你的问题,请参考以下文章

NOIP 2015 & SDOI 2016 Round1 & CTSC 2016 & SDOI2016 Round2游记

秋的潇洒在啥?在啥在啥?

上传的数据在云端的怎么查看,保存在啥位置?

在 React 应用程序中在哪里转换数据 - 在 Express 中还是在前端使用 React?

存储在 plist 中的数据在模拟器中有效,但在设备中无效

如何在保存在 Mongoose (ExpressJS) 之前在模型中格式化数据