mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
169 lines
5.7 KiB
Objective-C
Executable File
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
|