Giz*_*odo 13 uiscrollview ios uicollectionview uicollectionviewlayout swift
在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
})
}
Run Code Online (Sandbox Code Playgroud)
而不是使用' indexPathsForVisibleItems ',只使用' contentOffset '?计算偏移后的偏移?但是,当旋转后的contentSize可能与预期的不同单元尺寸,单元间距等不同时,这怎么可能呢?
jam*_*esk 30
您可以通过实现UICollectionViewDelegate方法来完成此操作collectionView(_:targetContentOffsetForProposedContentOffset:):
在布局更新期间,或在布局之间转换时,集合视图调用此方法,使您有机会更改要在动画结束时使用的建议内容偏移.如果布局或动画可能导致项目以不适合您的设计的方式定位,则可能会返回新值.
或者,如果您已经子类化了UICollectionViewLayout,则可以targetContentOffset(forProposedContentOffset:)在布局子类中实现,这可能更方便.
在您的方法实现中,计算并返回内容偏移量,该偏移量将导致中心单元格位于集合视图的中心.如果您的单元格大小是固定的,则应该简单地撤消由其他UI元素(例如状态栏和/或导航栏的消失帧)导致的内容偏移的更改.
如果您的单元格大小因设备方向而异:
indexPathForItem(at:)集合视图来获取并保存中心单元的索引路径,将内容偏移量(加上集合视图的可见边界的高度的一半)作为点传递.targetContentOffset(forProposedContentOffset:)方法.通过layoutAttributesForItem(at:)使用保存的索引路径调用来检索中心单元的布局属性.目标内容偏移量是该项目框架的中间位置(减少了集合视图可见边界高度的一半).第一步可以在视图控制器中viewWillTransition(to:with:)或中实现scrollViewDidScroll().它也可以在你的布局对象实施的prepareForAnimatedBoundsChange(),或者在invalidateLayout(with:)检查引起设备取向的变化范围变更后.(在这种情况下,您还需要确保shouldInvalidateLayout(forBoundsChange:)返回true.)
您可能需要针对内容插入,单元格间距或应用程序特定的其他事项进行调整.
这是实施jamesk solutuion在swift:
在您的ViewController中:
fileprivate var prevIndexPathAtCenter: IndexPath?
fileprivate var currentIndexPath: IndexPath? {
let center = view.convert(collectionView.center, to: collectionView)
return collectionView.indexPathForItem(at: center)
}
override func willTransition(to newCollection: UITraitCollection, with coordinator: UIViewControllerTransitionCoordinator) {
super.willTransition(to: newCollection, with: coordinator)
if let indexAtCenter = currentIndexPath {
prevIndexPathAtCenter = indexAtCenter
}
collectionView.collectionViewLayout.invalidateLayout()
}
Run Code Online (Sandbox Code Playgroud)
在UICollectionViewDelegateFlowLayout中:
func collectionView(_ collectionView: UICollectionView, targetContentOffsetForProposedContentOffset proposedContentOffset: CGPoint) -> CGPoint {
guard let oldCenter = prevIndexPathAtCenter else {
return proposedContentOffset
}
let attrs = collectionView.layoutAttributesForItem(at: oldCenter)
let newOriginForOldIndex = attrs?.frame.origin
return newOriginForOldIndex ?? proposedContentOffset
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4785 次 |
| 最近记录: |