增强iOS中UICollectionView布局之间的转换。
TLLayoutTransitioning提供了一个TLLayoutTransition
过渡布局子类和UICollectionView+TLTransitioning类别,结合使用可以解决一些集合视图布局转换的问题
UICollectionViewLayoutTransition
处理内容偏移效果不好,常常留下不需要的cell。《TLTransitionLayout》提供通过相对于一个或多个索引路径的最小、可见、中心、顶部、左侧、底部或右侧位置选项来控制内容偏移的一份优雅控制。
UICollectionViewLayoutTransition
不支持辅助视图。TLTransitionLayout
提供了对初始化器中指定的任何辅助视图类型的支持。
-[UICollectionView setCollectionViewLayout:animated:completion]
在iOS7中存在CADisplayLink
来驱动非交互式的TLTransitionLayout
作为交互式动画提供了对动画持续时间、30多个函数曲线和内容偏移控制的支持。通过这样做可以在交互式动画中使用CADisplayLink
,但是在更复杂的cell中可能不如核心动画的表现好。
在示例工作空间中检查演示!
TLTransitionLayout
是UICollectionViewTransitionLayout
的子类,它在线性插值布局之间以及(可选的)介于当前内容偏移和指定的最终偏移之间。
最终偏移通过设置toContentOffset
属性指定。通过UICollectionView+TLTransitioning
类别提供了一种计算相对于一个或多个索引路径的最小、可见、中心、顶部、左侧、底部或右侧偏移位置放置的API。
基本使用方法如下
- (void)someViewControllerEventHandler
{
UICollectionViewLayout *nextLayout = ...;
self.transitionLayout = (TLTransitionLayout *)[self.collectionView startInteractiveTransitionToCollectionViewLayout:nextLayout
completion:^(BOOL completed, BOOL finish) {
if (finish) {
self.collectionView.contentOffset = self.transitionLayout.toContentOffset;
self.transitionLayout = nil;
}
}];
NSArray *indexPaths = ...;// some selection of index paths to place
self.transitionLayout.toContentOffset = [self.collectionView toContentOffsetForLayout:self.transitionLayout indexPaths:indexPaths placement:TLTransitionLayoutIndexPathPlacementCenter];
}
- (UICollectionViewTransitionLayout *)collectionView:(UICollectionView *)collectionView transitionLayoutForOldLayout:(UICollectionViewLayout *)fromLayout newLayout:(UICollectionViewLayout *)toLayout
{
NSArray *supplementaryKinds = ...; // optional supplementary view kinds
return [[TLTransitionLayout alloc] initWithCurrentLayout:fromLayout nextLayout:toLayout supplementaryKinds:supplementaryKinds];
}
请注意,集合视图将在转换最终确定后重置contentOffset
,但如上图所示,这可以通过在完成块中将它重新设置为toContentOffset
来抵消。
如果您想停止当前转换从当前位置启动一个新的转换,您需要一种可以就地停止当前转换的方法。Apple提供了finishInteractiveTransition
和cancelInteractiveTransition
来结束转换,但是这两个都没有停止转换。所以,TLLayoutTransitioning提供了这样的方法
[self.collectionView cancelInteractiveTransitionInPlaceWithCompletion:^(){
// initiate new transition in the completion block
}];
您可以通过检查 UICollectionView
上的 isInteractiveTransitionInProgress
来确定是否正在执行过渡。
UICollectionView+TLTransitioning
分类提供了一些用于计算交互式过渡的有用方法。特别地,toContentOffsetForLayout:indexPaths:placement
API 计算最终内容偏移值,以实现针对一个或多个索引路径的最小、可见、居中、顶部、左侧、底部或右侧放置。此 API 的扩展版本提供了进一步的微调,并支持过渡到不同大小的集合视图和内容内边距。
- (CGPoint)toContentOffsetForLayout:(UICollectionViewTransitionLayout *)layout
indexPaths:(NSArray *)indexPaths
placement:(TLTransitionLayoutIndexPathPlacement)placement
placementAnchor:(CGPoint)placementAnchor
placementInset:(UIEdgeInsets)placementInset
toSize:(CGSize)toSize
toContentInset:(UIEdgeInsets)toContentInset
UICollectionView+TLTransitioning
还为非交互式动画之间的布局提供了一个对 -[UICollectionView setCollectionViewLayout:animated:completion]
的替代方案,支持动画持续时间、30 种内置的缓动曲线(由 Warren Moore 的 AHEasing 库提供)、用户定义的缓动曲线(通过定义自定义的 AHEasingFunctions
)和内容偏移控制。基本的过渡调用如下所示
TLTransitionLayout *layout = (TLTransitionLayout *)[collectionView transitionToCollectionViewLayout:toLayout duration:2 easing:QuarticEaseInOut completion:nil];
CGPoint toOffset = [collectionView toContentOffsetForLayout:layout indexPaths:@[indexPath] placement:TLTransitionLayoutIndexPathPlacementCenter];
layout.toContentOffset = toOffset;
其中视图控制器配置为提供上面描述的 TLTransitionLayout
实例。请查看 Examples 工作空间中的 Resize 示例项目,以查看其实际应用。
如果您没有使用依赖管理器,请查看 noframeworks 分支,并将以下文件复制到您的项目中
TLTransitionLayout.h
TLTransitionLayout.m
UICollectionView+TLTransitionAnimator.h
UICollectionView+TLTransitionAnimator.m
并从 AHEasing 复制以下文件
easing.h
easing.c
打开 Examples 工作空间(不是项目)以运行示例应用。以下示例被包含在内
调整大小示例将 TLTransitionLayout
和 -[UICollectionView+TLTransitioning transitionToCollectionViewLayout:duration:easing:completion:]
结合起来,作为 -[UICollectionView setCollectionViewLayout:animated:completion]
的一个更好的替代方案。在设置面板上尝试不同的持续时间、缓动曲线和内容偏移选项。切换“显示分区标题”以查看过渡辅助视图。
捏合示例展示了一个使用 TLTransitionLayout
的简单捏合驱动的交互式过渡。目标 contentOffset
被选择,使得初始可见的单元格保持在中心。或者如果单元格被点击,则将 contentOffset
设置为单元格居中。