From 9dda2fa8c0df42b336dd2a840a662828df91ffc4 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Thu, 10 Jan 2019 16:52:47 -0500 Subject: [PATCH 1/2] Improve scroll state continuity during conversation view rotations. --- .../ConversationViewController.m | 55 ++++++++++++++----- 1 file changed, 41 insertions(+), 14 deletions(-) diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m index 6f5c625c1..af2d9f148 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m @@ -4347,23 +4347,34 @@ typedef enum : NSUInteger { targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset { if (self.scrollContinuity == kScrollContinuityBottom && self.lastKnownDistanceFromBottom) { - // Adjust the content offset to reflect the "last known" distance - // from the bottom of the content. - CGFloat contentOffsetYBottom = self.maxContentOffsetY; - CGFloat contentOffsetY = contentOffsetYBottom - MAX(0, self.lastKnownDistanceFromBottom.floatValue); - CGFloat minContentOffsetY; - if (@available(iOS 11, *)) { - minContentOffsetY = -self.collectionView.safeAreaInsets.top; - } else { - minContentOffsetY = 0.f; + NSValue *_Nullable contentOffset = + [self contentOffsetForLastKnownDistanceFromBottom:self.lastKnownDistanceFromBottom.floatValue]; + if (contentOffset) { + proposedContentOffset = contentOffset.CGPointValue; } - contentOffsetY = MAX(minContentOffsetY, contentOffsetY); - proposedContentOffset.y = contentOffsetY; } return proposedContentOffset; } +// We use this hook to ensure scroll state continuity. As the collection +// view's content size changes, we want to keep the same cells in view. +- (nullable NSValue *)contentOffsetForLastKnownDistanceFromBottom:(CGFloat)lastKnownDistanceFromBottom +{ + // Adjust the content offset to reflect the "last known" distance + // from the bottom of the content. + CGFloat contentOffsetYBottom = self.maxContentOffsetY; + CGFloat contentOffsetY = contentOffsetYBottom - MAX(0, lastKnownDistanceFromBottom); + CGFloat minContentOffsetY; + if (@available(iOS 11, *)) { + minContentOffsetY = -self.collectionView.safeAreaInsets.top; + } else { + minContentOffsetY = 0.f; + } + contentOffsetY = MAX(minContentOffsetY, contentOffsetY); + return [NSValue valueWithCGPoint:CGPointMake(0, contentOffsetY)]; +} + #pragma mark - Scroll State - (BOOL)isScrolledToBottom @@ -4811,18 +4822,34 @@ typedef enum : NSUInteger { { [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]; + // Update and snapshot the "last known distance from bottom". + [self updateLastKnownDistanceFromBottom]; + NSNumber *_Nullable lastKnownDistanceFromBottom = self.lastKnownDistanceFromBottom; + __weak ConversationViewController *weakSelf = self; [coordinator animateAlongsideTransition:^(id context) { // Do nothing. } completion:^(id context) { + ConversationViewController *strongSelf = weakSelf; + if (!strongSelf) { + return; + } + // When transition animation is complete, update layout to reflect // new size. - [weakSelf resetForSizeOrOrientationChange]; + [strongSelf resetForSizeOrOrientationChange]; + + if (lastKnownDistanceFromBottom) { + NSValue *_Nullable contentOffsetValue = + [strongSelf contentOffsetForLastKnownDistanceFromBottom:lastKnownDistanceFromBottom.floatValue]; + if (contentOffsetValue) { + CGPoint contentOffset = contentOffsetValue.CGPointValue; + [strongSelf.collectionView setContentOffset:contentOffset animated:NO]; + } + } }]; - - // TODO: Ensure scroll state continuity? } - (void)traitCollectionDidChange:(nullable UITraitCollection *)previousTraitCollection From d32372ec26f1d6f3d7379508ae371b6a8da1555f Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Fri, 11 Jan 2019 16:45:02 -0500 Subject: [PATCH 2/2] Respond to CR. --- .../ConversationViewController.m | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m index af2d9f148..798311d1a 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m @@ -4822,14 +4822,17 @@ typedef enum : NSUInteger { { [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]; - // Update and snapshot the "last known distance from bottom". - [self updateLastKnownDistanceFromBottom]; - NSNumber *_Nullable lastKnownDistanceFromBottom = self.lastKnownDistanceFromBottom; + // Snapshot the "last visible row". + NSIndexPath *_Nullable lastVisibleIndexPath = self.lastVisibleIndexPath; __weak ConversationViewController *weakSelf = self; [coordinator animateAlongsideTransition:^(id context) { - // Do nothing. + if (lastVisibleIndexPath) { + [self.collectionView scrollToItemAtIndexPath:lastVisibleIndexPath + atScrollPosition:UICollectionViewScrollPositionBottom + animated:NO]; + } } completion:^(id context) { ConversationViewController *strongSelf = weakSelf; @@ -4841,13 +4844,10 @@ typedef enum : NSUInteger { // new size. [strongSelf resetForSizeOrOrientationChange]; - if (lastKnownDistanceFromBottom) { - NSValue *_Nullable contentOffsetValue = - [strongSelf contentOffsetForLastKnownDistanceFromBottom:lastKnownDistanceFromBottom.floatValue]; - if (contentOffsetValue) { - CGPoint contentOffset = contentOffsetValue.CGPointValue; - [strongSelf.collectionView setContentOffset:contentOffset animated:NO]; - } + if (lastVisibleIndexPath) { + [strongSelf.collectionView scrollToItemAtIndexPath:lastVisibleIndexPath + atScrollPosition:UICollectionViewScrollPositionBottom + animated:NO]; } }]; }