Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UITableView scrollViewDidScroll fired on animation

So most of the problems people have with this particular event is to have scrollViewDidScroll fire when there is animation happening. My case is just the opposite. I feel that scrollViewDidScroll should NOT be firing in my case.

Let me further explain.

I am animating things in scrollViewDidScroll and this was working perfectly until I moved UITableView into a UIView class.

- (void) scrollViewDidScroll:(UIScrollView *)scrollView {
   // Animation code here.
   NSLog(@"scrollViewDidScroll");
}

- (void) scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
   NSLog(@"scrollViewDidEndDecelerating");
   NSArray *indexPaths = [_myTableView indexPathsForVisibleRows];
   [_myTableView scrollToRowAtIndexPath:[indexPaths objectAtIndex:0] atScrollPosition:UITableViewScrollPositionTop animated:YES];
}


What this provides is a smooth scrolling experience that snaps back to a previous table row. The console can verify that scrollViewDidScroll event is firing because of scrollToRowAtIndexPath.

Console:

2014-03-31 22:21:43.346 Project[45843:a0b] scrollViewDidScroll
2014-03-31 22:21:43.379 Project[45843:a0b] scrollViewDidScroll
2014-03-31 22:21:43.429 Project[45843:a0b] scrollViewDidScroll
2014-03-31 22:21:43.462 Project[45843:a0b] scrollViewDidScroll
2014-03-31 22:21:43.479 Project[45843:a0b] scrollViewDidEndDecelerating
2014-03-31 22:21:43.496 Project[45843:a0b] scrollViewDidScroll
2014-03-31 22:21:43.513 Project[45843:a0b] scrollViewDidScroll
2014-03-31 22:21:43.529 Project[45843:a0b] scrollViewDidScroll

Onto the questions:

1. How can I ensure that the event scrollViewDidScroll only fires due to user interaction and not automation from code?

2. Is there another method that provides the same functionality as scrollToRowAtIndexPath without triggering scrollViewDidScroll?

like image 480
Levi Roberts Avatar asked Apr 01 '14 05:04

Levi Roberts


People also ask

What is contentOffset in scrollView?

contentOffset is the point at which the origin of the content view is offset from the origin of the scroll view. In other words, it is where the user has currently scrolled within the scroll view. This obviously changes as the user scrolls.

What is UIScrollView in swift?

Overview. UIScrollView is the superclass of several UIKit classes, including UITableView and UITextView . A scroll view is a view with an origin that's adjustable over the content view. It clips the content to its frame, which generally (but not necessarily) coincides with that of the app's main window.

Which is a property of UIScrollView?

→ UIScrollView has 3 main properties, known as contentSize, contentOffset, and contentInset.


2 Answers

I know this is a very old question. I just have been in a similar situation that I need to run some code only when the user is scrolling but not when I call scrollToRowAtIndexPath. I have found an easier solution for this using the scrollView variables dragging and decelerating.

we have 3 cases of scrolling here.

  1. user is dragging
  2. user just ended dragging and the tableview is decelrating
  3. programmatically called scrollForRowAtIndexPath:

All of the cases above will trigger scrollViewDidScroll: but

  1. user is dragging dragging is True and decelerating is False
  2. user just ended dragging and the tableview is decelrating dragging is False and decelerating is True
  3. programmatically called scrollForRowAtIndexPath: dragging is False and decelerating is False

So your code will be like something like this:

- (void) scrollViewDidScroll:(UIScrollView *)scrollView {
    if (scrollView.dragging)
     {
       // Do what you want when user is dragging
     } else if (scrollView.decelerating) 
     {
       // Do what you want when table is decelerating after finished dragging
     } else 
     {
       // Do what you want when table is scrolling programmatically.
     }
}

Or if you want to just distinguish the scrolling progammatically

- (void) scrollViewDidScroll:(UIScrollView *)scrollView {
    if (scrollView.dragging || scrollView.decelerating)
     {
       // Scrolling by the user
     } else 
     {
       // Scrolling by the code
     }
}
like image 65
Ismail Avatar answered Nov 15 '22 03:11

Ismail


Soon after I posted the question, I took a small break, came back to the problem and figured it out. Should of done that sooner instead of wasting a few hours. bleh!

The solution is simple, set a bool flag that gets set before any progammatic scrolling and then change that after the animation is done using the event scrollViewDidEndScrollingAnimation.

bool performingAutomatedScroll = false;

- (void) scrollViewDidScroll:(UIScrollView *)scrollView {

  // If we are scrolling because of code, don't use any animations.
  if (performingAutomatedScroll) return;

  // Animation code here.
}

- (void) scrollViewDidEndDecelerating:(UIScrollView *)scrollView {

  performingAutomatedScroll = true;
  NSArray *indexPaths = [_myTableView indexPathsForVisibleRows];
  [_myTableView scrollToRowAtIndexPath:[indexPaths objectAtIndex:0] atScrollPosition:UITableViewScrollPositionTop animated:YES];
  [_myTableView reloadRowsAtIndexPaths:[_timeCarousel indexPathsForVisibleRows] withRowAnimation:UITableViewRowAnimationNone];

}

- (void) scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {

  if (!decelerate) {
    performingAutomatedScroll = true;
    NSArray *indexPaths = [_myTableView indexPathsForVisibleRows];
    [_myTableView scrollToRowAtIndexPath:[indexPaths objectAtIndex:0] atScrollPosition:UITableViewScrollPositionTop animated:YES];
    [_myTableView reloadRowsAtIndexPaths:[_timeCarousel indexPathsForVisibleRows] withRowAnimation:UITableViewRowAnimationNone];
  }

}

-(void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView {
  performingAutomatedScroll = false;
}
like image 30
Levi Roberts Avatar answered Nov 15 '22 02:11

Levi Roberts