I have a view with a collectionView (single horizontal line) and a tableview below. Both view are synced while scrolling since they display the same data in different manners. In fact, it's like the "fantastical" app if you have this app.
I managed to sync both views using UIScrollView Delegate methods
#pragma mark - UIScrollViewDelegate
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
CGPoint currentOffset = scrollView.contentOffset;
NSLog(@"scrollViewDidScroll %@ - %@", NSStringFromCGPoint(scrollView.contentOffset), NSStringFromCGPoint(self.previousScrollOffset));
switch (self.scrollAnimation) {
case ScrollAnimationFromCollection:
{
if (currentOffset.x > self.previousScrollOffset.x && (self.scrollDirection == ScrollDirectionLeft || self.scrollDirection == ScrollDirectionNone))
{
// NSLog(@"Change to Right!");
self.scrollDirection = ScrollDirectionRight;
[self.alreadySelectedIndexPaths removeAllObjects];
}
else if (currentOffset.x <= self.previousScrollOffset.x && (self.scrollDirection == ScrollDirectionRight || self.scrollDirection == ScrollDirectionNone))
{
// NSLog(@"Change to Left!");
self.scrollDirection = ScrollDirectionLeft;
[self.alreadySelectedIndexPaths removeAllObjects];
}
[self moveTableView];
break;
}
case ScrollAnimationFromTableView:
{
if (currentOffset.y - self.previousScrollOffset.y > 0 && self.scrollDirection == ScrollDirectionBottom)
{
self.scrollDirection = ScrollDirectionTop;
[self.alreadySelectedIndexPaths removeAllObjects];
}
else if (currentOffset.y - self.previousScrollOffset.y <= 0 && self.scrollDirection == ScrollDirectionTop)
{
self.scrollDirection = ScrollDirectionBottom;
[self.alreadySelectedIndexPaths removeAllObjects];
}
[self moveCollectionView];
break;
}
default:
break;
}
self.previousScrollOffset = currentOffset;
}
#pragma mark - Move actions
- (void)moveCollectionView
{
NSIndexPath* currentIp = [[self.tableView indexPathsForVisibleRows] objectAtIndex:1];
NSLog(@"currentIp %@", currentIp);
if (![self.alreadySelectedIndexPaths containsObject:currentIp])
{
NSLog(@"Scroll to IndexPath centered!");
[self.alreadySelectedIndexPaths addObject:currentIp];
[self.collectionViewController.collectionView scrollToItemAtIndexPath:currentIp atScrollPosition:PSTCollectionViewScrollPositionCenteredHorizontally animated:YES];
}
}
- (void)moveTableView
{
NSIndexPath* currentIp = [self.collectionViewController.collectionView indexPathForItemAtPoint:[self.horizontalContainer convertPoint:self.horizontalContainer.center toView:self.collectionViewController.collectionView]];
NSLog(@"currentIp %@", currentIp);
if (![self.alreadySelectedIndexPaths containsObject:currentIp])
{
NSLog(@"Scroll to IndexPath At Top!");
[self.alreadySelectedIndexPaths addObject:currentIp];
self.tableView.decelerationRate = UIScrollViewDecelerationRateFast;
[self.tableView scrollToRowAtIndexPath:currentIp atScrollPosition:UITableViewScrollPositionTop animated:YES];
}
}
It works pretty great except for one thing : when I scroll the collectionview, the tableview takes some time to scroll due to the animated (YES) parameter. If I use scrollToRowAtIndexPath: with no animation, it works like a charm. But as soon as I use the animation flag, it seems (quite logically) that iOS queue the scrollToRowAtIndexPath and run them once at a time, resulting in a lag in the animation.
FWI, the alreadySelectedIndexPaths contains a list of indexPath to which I already scrolled (I don't know if this sentence is quite clear though :D :D)
I looked if there was a way to cancel the previous order, but apart from cancelPreviousPerformRequestsWithTarget: with cancels the last performSelector call, it didn't find anything useful.
Do you seen how can I manage to get a smooth animation here?
Thnaks for your help.
Override the scrollviewDidScroll method whenever the tableView or collectionView is scrolled.
In here you can take the offset of the view being scrolled and convert this into an offset for the other view.
Then you can just set this offset on the other view.
You don't need to animate to the offset or anything as the delegate method gets called within the animation loop anyway so just setting the offset will make it look like both views are being animated.
Hope this helps.