2020-02-22 15:38:54 +04:00

169 lines
5.7 KiB
Objective-C
Executable File

#import "TGTransitionLayout.h"
@interface TGTransitionLayout ()
{
NSDictionary *_poses;
NSDictionary *_targetPoses;
CGPoint _fromContentOffset;
}
@property (nonatomic) BOOL toContentOffsetInitialized;
@property (strong, nonatomic) NSDictionary *poses;
@property (nonatomic) CGFloat previousProgress;
@property (strong, nonatomic) NSArray *supplementaryKinds;
@end
@implementation TGTransitionLayout
- (instancetype)initWithCurrentLayout:(UICollectionViewLayout *)currentLayout nextLayout:(UICollectionViewLayout *)newLayout
{
self = [super initWithCurrentLayout:currentLayout nextLayout:newLayout];
if (self != nil)
{
_fromContentOffset = currentLayout.collectionView.contentOffset;
}
return self;
}
- (void)setTransitionProgress:(CGFloat)transitionProgress
{
if (self.transitionProgress != transitionProgress)
{
self.previousProgress = self.transitionProgress;
super.transitionProgress = transitionProgress;
if (self.toContentOffsetInitialized)
{
CGFloat t = self.transitionProgress;
CGFloat f = 1 - t;
CGPoint offset = CGPointMake(f * _fromContentOffset.x + t * self.toContentOffset.x, f * _fromContentOffset.y + t * self.toContentOffset.y);
self.collectionView.contentOffset = offset;
}
if (self.progressChanged != nil)
self.progressChanged(transitionProgress);
}
}
- (void)prepareLayout
{
[super prepareLayout];
CGFloat remaining = 1 - self.previousProgress;
CGFloat t = remaining == 0 ? self.transitionProgress : fabs(self.transitionProgress - self.previousProgress) / remaining;
CGFloat f = 1 - t;
NSMutableDictionary *poses = [[NSMutableDictionary alloc] init];
NSMutableDictionary *targetPoses = nil;
if (_targetPoses == nil)
{
targetPoses = [[NSMutableDictionary alloc] init];
_targetPoses = targetPoses;
}
for (NSInteger section = 0; section < [self.collectionView numberOfSections]; section++)
{
for (NSInteger item = 0; item < [self.collectionView numberOfItemsInSection:section]; item++)
{
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:item inSection:section];
NSIndexPath *key = [self keyForIndexPath:indexPath];
UICollectionViewLayoutAttributes *fromPose = self.poses != nil ? self.poses[key] : [self.currentLayout layoutAttributesForItemAtIndexPath:indexPath];
UICollectionViewLayoutAttributes *toPose = nil;
if (_targetPoses[key] != nil)
{
toPose = _targetPoses[key];
}
else
{
toPose = [self.nextLayout layoutAttributesForItemAtIndexPath:indexPath];
targetPoses[key] = toPose;
}
UICollectionViewLayoutAttributes *pose = nil;
if (t > DBL_EPSILON)
{
pose = [[[self class] layoutAttributesClass] layoutAttributesForCellWithIndexPath:indexPath];
[self interpolatePose:pose fromPose:fromPose toPose:toPose fromProgress:f toProgress:t];
}
else
{
pose = fromPose;
}
[poses setObject:pose forKey:key];
}
}
self.poses = poses;
}
- (void)interpolatePose:(UICollectionViewLayoutAttributes *)pose fromPose:(UICollectionViewLayoutAttributes *)fromPose toPose:(UICollectionViewLayoutAttributes *)toPose fromProgress:(CGFloat)f toProgress:(CGFloat)t
{
CGRect bounds = CGRectZero;
bounds.size.width = f * fromPose.bounds.size.width + t * toPose.bounds.size.width;
bounds.size.height = f * fromPose.bounds.size.height + t * toPose.bounds.size.height;
pose.bounds = bounds;
CGPoint center = CGPointZero;
center.x = f * fromPose.center.x + t * toPose.center.x;
center.y = f * fromPose.center.y + t * toPose.center.y;
pose.center = center;
}
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
NSMutableArray *poses = [NSMutableArray array];
for (NSInteger section = 0; section < [self.collectionView numberOfSections]; section++)
{
for (NSInteger item = 0; item < [self.collectionView numberOfItemsInSection:section]; item++)
{
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:item inSection:section];
UICollectionViewLayoutAttributes *pose = [self.poses objectForKey:indexPath];
CGRect intersection = CGRectIntersection(rect, pose.frame);
if (!CGRectIsEmpty(intersection))
[poses addObject:pose];
}
}
return poses;
}
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
id key = [self keyForIndexPath:indexPath];
return [self.poses objectForKey:key];
}
- (NSIndexPath *)keyForIndexPath:(NSIndexPath *)indexPath
{
if ([indexPath class] == [NSIndexPath class]) {
return indexPath;
}
return [NSIndexPath indexPathForRow:indexPath.row inSection:indexPath.section];
}
- (void)setToContentOffset:(CGPoint)toContentOffset
{
self.toContentOffsetInitialized = true;
if (!CGPointEqualToPoint(_toContentOffset, toContentOffset))
{
_toContentOffset = toContentOffset;
[self invalidateLayout];
}
}
- (void)collectionViewAlmostCompleteTransitioning:(UICollectionView *)__unused collectionView
{
if (self.transitionAlmostFinished != nil)
self.transitionAlmostFinished();
}
- (void)collectionViewDidCompleteTransitioning:(UICollectionView *)collectionView completed:(bool)__unused completed finish:(bool)__unused finish
{
if (finish && self.toContentOffsetInitialized)
collectionView.contentOffset = self.toContentOffset;
}
@end