Skip to content

Instantly share code, notes, and snippets.

@KanybekMomukeyev
Created January 5, 2016 06:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save KanybekMomukeyev/4adee58457ca6b95c6b1 to your computer and use it in GitHub Desktop.
Save KanybekMomukeyev/4adee58457ca6b95c6b1 to your computer and use it in GitHub Desktop.
Telegram to save correct cell position on interface orientation change
- (void)_performOrientationChangesWithDuration:(NSTimeInterval)duration orientation:(UIInterfaceOrientation)orientation
{
bool animated = duration > DBL_EPSILON;
CGSize collectionViewSize = [self collectionViewSizeForInterfaceOrientation:orientation];
CGFloat keyboardHeight = _keyboardHeight;
if (_titlePanelWrappingView != nil)
{
CGRect titleWrapperFrame = CGRectMake(0.0f, self.controllerInset.top, collectionViewSize.width, _titlePanelWrappingView.frame.size.height);
CGRect titlePanelFrame = CGRectMake(0.0f, 0.0f, titleWrapperFrame.size.width, _currentTitlePanel.frame.size.height);
if (duration > DBL_EPSILON)
{
[UIView animateWithDuration:duration animations:^
{
_titlePanelWrappingView.frame = titleWrapperFrame;
_currentTitlePanel.frame = titlePanelFrame;
}];
}
else
{
_titlePanelWrappingView.frame = titleWrapperFrame;
_currentTitlePanel.frame = titlePanelFrame;
}
}
[_currentInputPanel changeOrientationToOrientation:orientation keyboardHeight:keyboardHeight duration:duration];
CGFloat maxOriginY = _collectionView.contentOffset.y + _collectionView.contentInset.top;
CGPoint previousContentOffset = _collectionView.contentOffset;
CGRect previousCollectionFrame = _collectionView.frame;
int anchorItemIndex = -1;
CGFloat anchorItemOriginY = 0.0f;
CGFloat anchorItemRelativeOffset = 0.0f;
CGFloat anchorItemHeight = 0.0f;
NSMutableArray *previousItemFrames = [[NSMutableArray alloc] init];
CGRect previousVisibleBounds = CGRectMake(previousContentOffset.x, previousContentOffset.y, _collectionView.frame.size.width, _collectionView.frame.size.height);
NSMutableSet *previousVisibleItemIndices = [[NSMutableSet alloc] init];
std::vector<TGDecorationViewAttrubutes> previousDecorationAttributes;
NSArray *previousLayoutAttributes = [_collectionLayout layoutAttributesForItems:_items containerWidth:previousCollectionFrame.size.width maxHeight:FLT_MAX decorationViewAttributes:&previousDecorationAttributes contentHeight:NULL];
int collectionItemCount = _items.count;
for (int i = 0; i < collectionItemCount; i++)
{
UICollectionViewLayoutAttributes *attributes = previousLayoutAttributes[i];
CGRect itemFrame = attributes.frame;
if (itemFrame.origin.y < maxOriginY)
{
anchorItemHeight = itemFrame.size.height;
anchorItemIndex = i;
anchorItemOriginY = itemFrame.origin.y;
}
if (!CGRectIsEmpty(CGRectIntersection(itemFrame, previousVisibleBounds)))
[previousVisibleItemIndices addObject:@(i)];
[previousItemFrames addObject:[NSValue valueWithCGRect:itemFrame]];
}
if (anchorItemIndex != -1)
{
if (anchorItemHeight > 1.0f)
anchorItemRelativeOffset = (anchorItemOriginY - (_collectionView.contentOffset.y + _collectionView.contentInset.top)) / anchorItemHeight;
}
_collectionView.frame = CGRectMake(0, 0, collectionViewSize.width, collectionViewSize.height);
[_companion _setControllerWidthForItemCalculation:_collectionView.frame.size.width];
[_collectionLayout invalidateLayout];
UIEdgeInsets originalInset = _collectionView.contentInset;
UIEdgeInsets inset = originalInset;
inset.top = keyboardHeight + _currentInputPanel.frame.size.height;
inset.bottom = self.controllerInset.top;
_collectionView.contentInset = inset;
[self _updateUnseenMessagesButton:orientation];
[_emptyListPlaceholder adjustLayoutForOrientation:orientation contentInsets:UIEdgeInsetsMake(_collectionView.contentInset.bottom, 0.0f, _collectionView.contentInset.top, 0.0f) duration:duration curve:0];
CGFloat newContentHeight = 0.0f;
std::vector<TGDecorationViewAttrubutes> newDecorationAttributes;
NSArray *newLayoutAttributes = [_collectionLayout layoutAttributesForItems:_items containerWidth:_collectionView.frame.size.width maxHeight:FLT_MAX decorationViewAttributes:&newDecorationAttributes contentHeight:&newContentHeight];
CGPoint newContentOffset = _collectionView.contentOffset;
newContentOffset.y = - _collectionView.contentInset.top;
if (anchorItemIndex >= 0 && anchorItemIndex < (int)newLayoutAttributes.count)
{
UICollectionViewLayoutAttributes *attributes = newLayoutAttributes[anchorItemIndex];
newContentOffset.y += attributes.frame.origin.y - floorf(anchorItemRelativeOffset * attributes.frame.size.height);
}
if (newContentOffset.y > newContentHeight + _collectionView.contentInset.bottom - _collectionView.frame.size.height)
newContentOffset.y = newContentHeight + _collectionView.contentInset.bottom - _collectionView.frame.size.height;
if (newContentOffset.y < -_collectionView.contentInset.top)
newContentOffset.y = -_collectionView.contentInset.top;
NSMutableArray *transitiveItemIndicesWithFrames = [[NSMutableArray alloc] init];
CGRect newVisibleBounds = CGRectMake(newContentOffset.x, newContentOffset.y, _collectionView.frame.size.width, _collectionView.frame.size.height);
for (int i = 0; i < collectionItemCount; i++)
{
UICollectionViewLayoutAttributes *attributes = newLayoutAttributes[i];
CGRect itemFrame = attributes.frame;
if (CGRectIsEmpty(CGRectIntersection(itemFrame, newVisibleBounds)) && [previousVisibleItemIndices containsObject:@(i)])
[transitiveItemIndicesWithFrames addObject:@[@(i), [NSValue valueWithCGRect:itemFrame]]];
}
NSMutableDictionary *transitiveCells = [[NSMutableDictionary alloc] init];
if (animated && !_collectionView.decelerating && !_collectionView.dragging && !_collectionView.tracking)
{
for (NSArray *nDesc in transitiveItemIndicesWithFrames)
{
NSNumber *nIndex = nDesc[0];
TGModernCollectionCell *currentCell = (TGModernCollectionCell *)[_collectionView cellForItemAtIndexPath:[NSIndexPath indexPathForItem:[nIndex intValue] inSection:0]];
if (currentCell != nil)
{
TGModernCollectionCell *transitiveCell = [[TGModernCollectionCell alloc] initWithFrame:[nDesc[1] CGRectValue]];
[(TGModernConversationItem *)_items[[nIndex intValue]] moveToCell:transitiveCell];
transitiveCells[nIndex] = transitiveCell;
}
}
}
_collectionView.contentOffset = newContentOffset;
[_collectionView updateVisibleItemsNow];
[_collectionView layoutSubviews];
if (animated)
{
_collectionView.clipsToBounds = false;
CGFloat contentOffsetDifference = newContentOffset.y - previousContentOffset.y + (_collectionView.frame.size.height - previousCollectionFrame.size.height);
CGFloat widthDifference = _collectionView.frame.size.width - previousCollectionFrame.size.width;
NSMutableArray *itemFramesToRestore = [[NSMutableArray alloc] init];
bool contentUpdatesWereDisabled = _companion.viewContext.contentUpdatesDisabled;
_companion.viewContext.contentUpdatesDisabled = true;
for (int i = 0; i < collectionItemCount; i++)
{
TGModernCollectionCell *cell = (TGModernCollectionCell *)[_collectionView cellForItemAtIndexPath:[NSIndexPath indexPathForRow:i inSection:0]];
TGModernCollectionCell *transitiveCell = transitiveCells[@(i)];
if (transitiveCell != nil)
{
if (cell == nil)
{
cell = transitiveCell;
[_collectionView addSubview:transitiveCell];
}
else
{
if ([_items[i] boundCell] == transitiveCell)
[_items[i] moveToCell:cell];
[transitiveCells removeObjectForKey:@(i)];
}
}
if (cell != nil)
{
[itemFramesToRestore addObject:@[@(i), [NSValue valueWithCGRect:cell.frame]]];
CGRect previousFrame = [previousItemFrames[i] CGRectValue];
cell.frame = CGRectOffset(previousFrame, widthDifference, contentOffsetDifference);
TGModernConversationItem *item = _items[i];
[item sizeForContainerSize:CGSizeMake(previousFrame.size.width, 0.0f)];
}
}
for (auto it = previousDecorationAttributes.begin(); it != previousDecorationAttributes.end(); it++)
{
UIView *decorationView = [_collectionView viewForDecorationAtIndex:it->index];
decorationView.frame = CGRectOffset(it->frame, widthDifference, contentOffsetDifference);
[decorationView layoutSubviews];
}
[UIView animateWithDuration:duration animations:^
{
for (NSArray *frameDesc in itemFramesToRestore)
{
UIView *cell = [_collectionView cellForItemAtIndexPath:[NSIndexPath indexPathForRow:[frameDesc[0] intValue] inSection:0]];
if (cell == nil)
cell = transitiveCells[frameDesc[0]];
cell.frame = [frameDesc[1] CGRectValue];
TGModernConversationItem *item = _items[[frameDesc[0] intValue]];
[item sizeForContainerSize:CGSizeMake(_collectionView.frame.size.width, 0.0f)];
}
for (auto it = newDecorationAttributes.begin(); it != newDecorationAttributes.end(); it++)
{
UIView *decorationView = [_collectionView viewForDecorationAtIndex:it->index];
decorationView.frame = it->frame;
[decorationView layoutSubviews];
}
} completion:^(BOOL finished)
{
if (finished)
{
_collectionView.clipsToBounds = true;
}
[transitiveCells enumerateKeysAndObjectsUsingBlock:^(NSNumber *nIndex, TGModernCollectionCell *cell, __unused BOOL *stop)
{
[(TGModernConversationItem *)_items[[nIndex intValue]] unbindCell:_viewStorage];
[cell removeFromSuperview];
}];
}];
_companion.viewContext.contentUpdatesDisabled = contentUpdatesWereDisabled;
[_collectionView updateRelativeBounds];
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment