在Apple的Photo’s App上,如果在滚动到任意偏移的同时旋转设备,预先在中心的相同单元将在旋转后终止于中心.
我试图用UICollectionView实现相同的行为. ‘indexPathsForVisibleItems’似乎是这样做的方式….
到目前为止我得到了什么:
以下代码提供了旋转之间的平滑操作,但中心项计算似乎是关闭的:
override func viewWillTransition(to size: CGSize,with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size,with: coordinator) self.collectionView?.collectionViewLayout.invalidateLayout() let middleItem = (self.collectionView?.indexPathsForVisibleItems.count / 2) - 1 let indexPath = self.collectionView?.indexPathsForVisibleItems[middleItem] coordinator.animate(alongsideTransition: { ctx in self.collectionView?.layoutIfNeeded() self.collectionView?.scrollToItem(at: indexPath!,at: .centeredVertically,animated: false) },completion: { _ in }) }
什么不适用于上述代码:
>肖像 – >风景:从哪个细胞应该在中心结束.
>肖像 – >风景 – >肖像:完全偏离肖像中的偏移量.
>肖像 – >风景 – >肖像 – >风景:离开!
笔记:
>我必须在旋转时使集合视图布局无效
必须重新计算单元尺寸和间距.
> self.collectionView?.layoutIfNeeded()在动画中
阻止,使过渡平稳
>可以在集合视图之前调用scrollToItem
布局未最终确定,导致滚动偏移不正确?
替代方法?
而不是使用’indexPathsForVisibleItems’,只使用’contentOffset’?计算偏移后的偏移?但是,当旋转后的contentSize可能与预期的不同单元尺寸,单元间距等不同时,这怎么可能呢?
解决方法
collectionView(_:targetContentOffsetForProposedContentOffset:)
来完成此操作:
During layout updates,or when transitioning between layouts,the collection view calls this method to give you the opportunity to change the proposed content offset to use at the end of the animation. You might return a new value if the layout or animations might cause items to be positioned in a way that is not optimal for your design.
或者,如果您已经子类化了UICollectionViewLayout,则可以在布局子类中实现targetContentOffset(forProposedContentOffset:)
,这可能更方便.
在您的方法实现中,计算并返回内容偏移量,该偏移量将导致中心单元格位于集合视图的中心.如果您的单元格大小是固定的,则应该简单地撤消由其他UI元素(例如状态栏和/或导航栏的消失帧)导致的内容偏移的更改.
如果您的单元格大小因设备方向而异:
>在设备旋转之前,通过在集合视图上调用indexPathForItem(at:)
来获取并保存中心单元的索引路径,将内容偏移量(加上集合视图的可见边界的高度的一半)作为点.
>实现targetContentOffset(forProposedContentOffset :)方法之一.通过使用保存的索引路径调用layoutAttributesForItem(at :)来检索中心单元格的布局属性.目标内容偏移量是该项目框架的中间位置(减少了集合视图可见边界高度的一半).
第一步可以在viewWillTransition(to:with :)或scrollViewDidScroll()中的视图控制器中实现.它也可以在prepareForAnimatedBoundsChange()中的布局对象中实现,或者在检查由设备方向更改引起的边界更改后,可能在invalidateLayout(with :)中实现. (您还需要确保在这种情况下,shouldInvalidateLayout(forBoundsChange :)返回true.)
您可能需要针对内容插入,单元格间距或应用程序特定的其他事项进行调整.