diff --git a/Riot/ViewController/RecentsViewController.h b/Riot/ViewController/RecentsViewController.h
index c98f43d6f..786480a57 100644
--- a/Riot/ViewController/RecentsViewController.h
+++ b/Riot/ViewController/RecentsViewController.h
@@ -45,7 +45,6 @@
@property (weak, nonatomic) IBOutlet UIView *stickyHeadersBottomContainer;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *stickyHeadersTopContainerHeightConstraint;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *stickyHeadersBottomContainerHeightConstraint;
-@property (weak, nonatomic) IBOutlet NSLayoutConstraint *stickyHeadersBottomContainerBottomConstraint;
/**
If YES, the table view will scroll at the top on the next data source refresh.
@@ -94,9 +93,9 @@
- (void)resetStickyHeaders;
/**
- Update the sticky headers display.
+ Prepare the sticky headers display.
*/
-- (void)updateStickyHeaders;
+- (void)prepareStickyHeaders;
/**
Refresh the cell selection in the table.
diff --git a/Riot/ViewController/RecentsViewController.m b/Riot/ViewController/RecentsViewController.m
index 0cce00690..407bdd949 100644
--- a/Riot/ViewController/RecentsViewController.m
+++ b/Riot/ViewController/RecentsViewController.m
@@ -124,17 +124,6 @@
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
- // Adjust Bottom constraint to take into account tabBar.
- [NSLayoutConstraint deactivateConstraints:@[_stickyHeadersBottomContainerBottomConstraint]];
- _stickyHeadersBottomContainerBottomConstraint = [NSLayoutConstraint constraintWithItem:self.bottomLayoutGuide
- attribute:NSLayoutAttributeTop
- relatedBy:NSLayoutRelationEqual
- toItem:self.stickyHeadersBottomContainer
- attribute:NSLayoutAttributeBottom
- multiplier:1.0f
- constant:0.0f];
- [NSLayoutConstraint activateConstraints:@[_stickyHeadersBottomContainerBottomConstraint]];
-
self.recentsTableView.accessibilityIdentifier = @"RecentsVCTableView";
// Register here the customized cell view class used to render recents
@@ -277,8 +266,12 @@
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
+
+ dispatch_async(dispatch_get_main_queue(), ^{
- [self refreshStickyHeadersContainersHeight];
+ [self refreshStickyHeadersContainersHeight];
+
+ });
}
#pragma mark - Override MXKRecentListViewController
@@ -312,10 +305,13 @@
isRefreshPending = NO;
+ // Force reset existing sticky headers if any
+ [self resetStickyHeaders];
+
[self.recentsTableView reloadData];
// Check conditions to display the fake search bar into the table header
- if (_enableSearchBar && !_enableStickyHeaders && self.recentsSearchBar.isHidden && self.recentsTableView.tableHeaderView != tableSearchBar)
+ if (_enableSearchBar && self.recentsSearchBar.isHidden && self.recentsTableView.tableHeaderView == nil)
{
// Add the search bar by hiding it by default.
self.recentsTableView.tableHeaderView = tableSearchBar;
@@ -328,7 +324,7 @@
_shouldScrollToTopOnRefresh = NO;
}
- [self updateStickyHeaders];
+ [self prepareStickyHeaders];
// In case of split view controller where the primary and secondary view controllers are displayed side-by-side on screen,
// the selected room (if any) is updated and kept visible.
@@ -338,30 +334,13 @@
}
}
-- (void)setKeyboardHeight:(CGFloat)keyboardHeight
-{
- // Deduce the bottom constraint for the table view (Don't forget the potential tabBar)
- CGFloat tableViewBottomConst = keyboardHeight - self.bottomLayoutGuide.length;
- // Check whether the keyboard is over the tabBar
- if (tableViewBottomConst < 0)
- {
- tableViewBottomConst = 0;
- }
-
- // Update constraints
- _stickyHeadersBottomContainerBottomConstraint.constant = tableViewBottomConst;
-
- // Force layout immediately to take into account new constraint
- [self.view layoutIfNeeded];
-}
-
- (void)hideSearchBar:(BOOL)hidden
{
[super hideSearchBar:hidden];
- if (!hidden && !_enableStickyHeaders)
+ if (!hidden)
{
- // Remove the fake table header view
+ // Remove the fake table header view if any
self.recentsTableView.tableHeaderView = nil;
self.recentsTableView.contentInset = UIEdgeInsetsZero;
}
@@ -409,24 +388,11 @@
{
_enableStickyHeaders = enableStickyHeaders;
- if (enableStickyHeaders)
+ // Refresh the table display if it is already rendered.
+ if (self.recentsTableView.contentSize.height)
{
- // Add a table header view in order to hide the current section header stuck in floating mode at the top of the table.
- // This section header is handled then by a sticky header.
- UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.recentsTableView.bounds.size.width, self.stickyHeaderHeight)];
- self.recentsTableView.tableHeaderView = headerView;
- self.recentsTableView.contentInset = UIEdgeInsetsMake(-self.stickyHeaderHeight, 0, 0, 0);
-
- [self.recentsSearchBar setShowsCancelButton:NO animated:NO];
+ [self refreshRecentsTable];
}
- else
- {
- self.recentsTableView.tableHeaderView = nil;
- self.recentsTableView.contentInset = UIEdgeInsetsZero;
- }
-
-
- [self refreshRecentsTable];
}
- (void)setStickyHeaderHeight:(CGFloat)stickyHeaderHeight
@@ -462,13 +428,13 @@
}
[displayedSectionHeaders removeAllObjects];
- firstDisplayedSectionHeaderPosY = 0;
+
+ self.recentsTableView.contentInset = UIEdgeInsetsZero;
}
-- (void)updateStickyHeaders
+- (void)prepareStickyHeaders
{
- // Force reset existing sticky headers if any
- [self resetStickyHeaders];
+ // We suppose here [resetStickyHeaders] has been already called if need.
NSInteger sectionsCount = self.recentsTableView.numberOfSections;
@@ -575,135 +541,84 @@
{
if (_enableStickyHeaders)
{
- // Check whether the full table content is visible.
- if (self.recentsTableView.contentSize.height + self.recentsTableView.contentInset.top + self.recentsTableView.contentInset.bottom <= self.recentsTableView.frame.size.height )
- {
- // No sticky header is required. Hide them to prevent from flickering in case of vertical bounces.
- self.stickyHeadersTopContainerHeightConstraint.constant = 0;
- self.stickyHeadersBottomContainerHeightConstraint.constant = 0;
- return;
- }
-
- // Retrieve the first and the last headers actually visible in the recents table view.
- // Caution: In some cases like the screen rotation, some displayed section headers are temporarily not visible.
- UIView *firstDisplayedSectionHeader, *lastDisplayedSectionHeader;
+ NSUInteger lowestSectionInBottomStickyHeader = NSNotFound;
CGFloat containerHeight;
- CGFloat maxVisiblePosY = self.recentsTableView.contentOffset.y + self.recentsTableView.frame.size.height - self.recentsTableView.contentInset.bottom;
+ // Retrieve the first header actually visible in the recents table view.
+ // Caution: In some cases like the screen rotation, some displayed section headers are temporarily not visible.
+ UIView *firstDisplayedSectionHeader;
for (UIView *header in displayedSectionHeaders)
{
- if (!firstDisplayedSectionHeader)
+ if (header.frame.origin.y + header.frame.size.height > self.recentsTableView.contentOffset.y)
{
- if (header.frame.origin.y + header.frame.size.height > self.recentsTableView.contentOffset.y)
- {
- firstDisplayedSectionHeader = lastDisplayedSectionHeader = header;
- }
- }
- else
- {
- if (header.frame.origin.y < maxVisiblePosY)
- {
- lastDisplayedSectionHeader = header;
- }
- else
- {
- break;
- }
+ firstDisplayedSectionHeader = header;
+ break;
}
}
if (firstDisplayedSectionHeader)
{
- // Consider the first visible section header to update the height of the top container of the sticky headers.
- // Check whether the header positon is not floating.
- if (firstDisplayedSectionHeader.frame.origin.y == firstDisplayedSectionHeaderPosY)
+ // Initialize the top container height by considering the headers which are before the first visible section header.
+ containerHeight = 0;
+ for (UIView *header in _stickyHeadersTopContainer.subviews)
+ {
+ if (header.tag < firstDisplayedSectionHeader.tag)
+ {
+ containerHeight += self.stickyHeaderHeight;
+ }
+ }
+
+ // Check whether the first visible section header is partially hidden.
+ if (firstDisplayedSectionHeader.frame.origin.y < self.recentsTableView.contentOffset.y)
{
// Compute the height of the hidden part.
CGFloat delta = self.recentsTableView.contentOffset.y - firstDisplayedSectionHeader.frame.origin.y;
- if (delta < 0)
- {
- delta = 0;
- }
- // Compute the top container height.
- containerHeight = 0;
- for (UIView *header in _stickyHeadersTopContainer.subviews)
+ if (delta < self.stickyHeaderHeight)
{
- if (header.tag < firstDisplayedSectionHeader.tag)
- {
- containerHeight += header.frame.size.height;
- }
- else if (header.tag == firstDisplayedSectionHeader.tag)
- {
- if (delta < header.frame.size.height)
- {
- containerHeight += delta;
- }
- else
- {
- containerHeight += header.frame.size.height;
- }
- }
+ containerHeight += delta;
}
-
+ else
+ {
+ containerHeight += self.stickyHeaderHeight;
+ }
+ }
+
+ if (containerHeight)
+ {
self.stickyHeadersTopContainerHeightConstraint.constant = containerHeight;
+ self.recentsTableView.contentInset = UIEdgeInsetsMake(-self.stickyHeaderHeight, 0, 0, 0);
}
else
{
- // Update the first displayed header position.
- firstDisplayedSectionHeaderPosY = firstDisplayedSectionHeader.frame.origin.y;
-
- // The first displayed header position is floating, that means the header is stuck at the top of the table.
- // We hide its higher part with the sticky header. The lower part of the header is still visible if its height
- // is higher than self.stickyHeaderHeight.
- containerHeight = 0;
- for (UIView *header in _stickyHeadersTopContainer.subviews)
- {
- if (header.tag <= firstDisplayedSectionHeader.tag)
- {
- containerHeight += header.frame.size.height;
- }
- }
-
- self.stickyHeadersTopContainerHeightConstraint.constant = containerHeight;
+ self.stickyHeadersTopContainerHeightConstraint.constant = 0;
+ self.recentsTableView.contentInset = UIEdgeInsetsZero;
}
- // Consider the last visible section header to update the height of the bottom container of the sticky headers.
- containerHeight = 0;
- CGRect bounds = self.stickyHeadersBottomContainer.frame;
- bounds.origin.y = 0;
+ // Look for the lowest section index visible in the bottom sticky headers.
+ CGFloat maxVisiblePosY = self.recentsTableView.contentOffset.y + self.recentsTableView.frame.size.height - self.recentsTableView.contentInset.bottom;
+ UIView *lastDisplayedSectionHeader = displayedSectionHeaders.lastObject;
+
for (UIView *header in _stickyHeadersBottomContainer.subviews)
{
- if (header.tag == lastDisplayedSectionHeader.tag)
+ if (header.tag > lastDisplayedSectionHeader.tag)
{
- // Compute the height of the hidden part
- CGFloat delta = (lastDisplayedSectionHeader.frame.origin.y + header.frame.size.height) - maxVisiblePosY;
- if (delta < 0)
- {
- delta = 0;
- }
-
- if (delta < header.frame.size.height)
- {
- bounds.origin.y = header.frame.origin.y + header.frame.size.height - delta;
- containerHeight += delta;
- }
- else
- {
- bounds.origin.y = header.frame.origin.y;
- containerHeight += header.frame.size.height;
- }
- }
- else if (header.tag > lastDisplayedSectionHeader.tag)
- {
- containerHeight += header.frame.size.height;
+ maxVisiblePosY -= self.stickyHeaderHeight;
}
}
- if (self.stickyHeadersBottomContainerHeightConstraint.constant != containerHeight)
+ for (NSInteger index = displayedSectionHeaders.count; index > 0;)
{
- self.stickyHeadersBottomContainerHeightConstraint.constant = containerHeight;
- self.stickyHeadersBottomContainer.bounds = bounds;
+ lastDisplayedSectionHeader = displayedSectionHeaders[--index];
+ if (lastDisplayedSectionHeader.frame.origin.y + self.stickyHeaderHeight > maxVisiblePosY)
+ {
+ maxVisiblePosY -= self.stickyHeaderHeight;
+ }
+ else
+ {
+ lowestSectionInBottomStickyHeader = lastDisplayedSectionHeader.tag + 1;
+ break;
+ }
}
}
else
@@ -726,26 +641,43 @@
}
self.stickyHeadersTopContainerHeightConstraint.constant = containerHeight;
-
- // Update the bottom container of the sticky headers.
- containerHeight = 0;
- CGRect bounds = self.stickyHeadersBottomContainer.frame;
- for (UIView *header in _stickyHeadersBottomContainer.subviews)
+ if (containerHeight)
{
- if (header.tag > section)
- {
- if (header.tag == section + 1)
- {
- bounds.origin.y = header.frame.origin.y;
- }
-
- containerHeight += header.frame.size.height;
- }
+ self.recentsTableView.contentInset = UIEdgeInsetsMake(-self.stickyHeaderHeight, 0, 0, 0);
}
- self.stickyHeadersBottomContainerHeightConstraint.constant = containerHeight;
- self.stickyHeadersBottomContainer.bounds = bounds;
+ else
+ {
+ self.recentsTableView.contentInset = UIEdgeInsetsZero;
+ }
+
+ // Set the lowest section index visible in the bottom sticky headers.
+ lowestSectionInBottomStickyHeader = section + 1;
}
}
+
+ // Update here the height of the bottom container of the sticky headers thanks to lowestSectionInBottomStickyHeader.
+ containerHeight = 0;
+ CGRect bounds = _stickyHeadersBottomContainer.frame;
+ bounds.origin.y = 0;
+
+ for (UIView *header in _stickyHeadersBottomContainer.subviews)
+ {
+ if (header.tag > lowestSectionInBottomStickyHeader)
+ {
+ containerHeight += self.stickyHeaderHeight;
+ }
+ else if (header.tag == lowestSectionInBottomStickyHeader)
+ {
+ containerHeight += self.stickyHeaderHeight;
+ bounds.origin.y = header.frame.origin.y;
+ }
+ }
+
+ if (self.stickyHeadersBottomContainerHeightConstraint.constant != containerHeight)
+ {
+ self.stickyHeadersBottomContainerHeightConstraint.constant = containerHeight;
+ self.stickyHeadersBottomContainer.bounds = bounds;
+ }
}
}
@@ -1194,7 +1126,6 @@
if (!firstDisplayedSectionHeader || section < firstDisplayedSectionHeader.tag)
{
[displayedSectionHeaders insertObject:view atIndex:0];
- firstDisplayedSectionHeaderPosY = view.frame.origin.y;
}
else
{
@@ -1216,10 +1147,6 @@
{
[displayedSectionHeaders removeObjectAtIndex:0];
- // Update first displayed section position
- firstDisplayedSectionHeader = displayedSectionHeaders.firstObject;
- firstDisplayedSectionHeaderPosY = firstDisplayedSectionHeader.frame.origin.y;
-
[self refreshStickyHeadersContainersHeight];
}
else
@@ -1242,7 +1169,11 @@
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
- [self refreshStickyHeadersContainersHeight];
+ dispatch_async(dispatch_get_main_queue(), ^{
+
+ [self refreshStickyHeadersContainersHeight];
+
+ });
[super scrollViewDidScroll:scrollView];
@@ -1254,6 +1185,9 @@
{
// Hide the search bar
[self hideSearchBar:YES];
+
+ // Refresh display
+ [self refreshRecentsTable];
}
}
}
@@ -1698,12 +1632,6 @@
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
{
[super scrollViewWillEndDragging:scrollView withVelocity:velocity targetContentOffset:targetContentOffset];
-
- if (_enableStickyHeaders && _enableSearchBar && targetContentOffset->y + scrollView.contentInset.top <= 0 && scrollView.contentSize.height)
- {
- // Show the search bar
- [self hideSearchBar:NO];
- }
}
- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar
diff --git a/Riot/ViewController/RecentsViewController.xib b/Riot/ViewController/RecentsViewController.xib
index 348c4ef12..9eb164746 100644
--- a/Riot/ViewController/RecentsViewController.xib
+++ b/Riot/ViewController/RecentsViewController.xib
@@ -15,8 +15,8 @@
+
-
@@ -61,18 +61,18 @@
+
+
-
-