Created
January 5, 2016 06:02
-
-
Save KanybekMomukeyev/4adee58457ca6b95c6b1 to your computer and use it in GitHub Desktop.
Telegram to save correct cell position on interface orientation change
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
- (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