Setting contentOffset programmatically starts scrollViewDidScroll

I have several UIScrollView on the page. You can scroll them yourself or lock them together and scroll them as one. The problem occurs when they are locked.

I use UIScrollViewDelegate and scrollViewDidScroll: to track movement. I request a contentOffset from a UIScrollView that has been modified, and then reflect the changes in other scroll views by setting their contentOffset property to match.

Great .... except that I noticed a lot of extra calls. Programmatically changing the contentOffset my scroll views triggers the scrollViewDidScroll: delegate method to call. I tried using setContentOffset:animated: instead, but I'm still getting a deletion trigger.

How can I programmatically modify my programmatic content objects so as not to trigger scrollViewDidScroll: :?

Implementation notes .... Each UIScrollView is part of a custom UIView that uses a delegation pattern to call back to the representing subclass of the UIViewController , which handles the coordinates of various contentOffset values.

+48
ios uiscrollview uiscrollviewdelegate
Feb 23 '12 at 17:45
source share
6 answers

You can change the UIScrollView content offset without triggering the scrollViewDidScroll: delegate scrollViewDidScroll: setting the boundaries of the UIScrollView with the original value set to the desired content offset.

 CGRect scrollBounds = scrollView.bounds; scrollBounds.origin = desiredContentOffset; scrollView.bounds = scrollBounds; 
+89
Feb 23 '12 at 18:05
source share

Try

 id scrollDelegate = scrollView.delegate; scrollView.delegate = nil; scrollView.contentOffset = point; scrollView.delegate = scrollDelegate; 

Worked for me.

+59
Jul 25 '13 at 11:10
source share

How to use existing UIScrollView properties?

 if(scrollView.isTracking || scrollView.isDragging || scrollView.isDecelerating) { //your code } 
+25
Nov 08 '14 at 16:35
source share

Simplifying @Tark's answer, you can put scrollViewDidScroll without firing on one line as follows:

 scrollView.bounds.origin = CGPoint(x:0, y:100); // whatever values you'd like 
+6
Mar 10 '15 at 12:33
source share

This is not a direct answer to the question, but if you get what seems to be false, such messages, it could also be because you are changing boundaries. I am using Apple sample code with the "tilePages" method, which removes and adds subview to scrollview. This rarely leads to additional scrollViewDidScroll: messages being called immediately, so you end up in a recursion that you definitely did not expect. In my case, I got a disgusting impossible to find a crash.

What I ended up with was the order of the call in the main queue:

 - (void)scrollViewDidScroll:(UIScrollView *)scrollView { if(scrollView == yourScrollView) { // dispatch fixes some recursive call to scrollViewDidScroll in tilePages (related to removeFromSuperView) // The reason can be found here: http://stackoverflow.com/questions/9418311 dispatch_async(dispatch_get_main_queue(), ^{ [self tilePages]; }); } } 
+4
Mar 31 '12 at 21:00
source share

Another approach is to add some logic to the scrollViewDidScroll delegate to determine if a change in the content offset has been programmed or pressed by the user.

  • Add the boolean variable isManualScroll to your class.
  • Set the initial value to false.
  • ScrollViewWillBeginDragging is set to true.
  • In your scrollViewDidScroll check, make sure it is true, and only answer if there is one.
  • In scrollViewDidEndDecelerating set to false.
  • In scrollViewWillEndDragging, add logic to set the value to false if the speed is 0 (since scrollViewDidEndDecelerating will not be called in this case).
+4
Sep 11 '14 at 1:39 on
source share



All Articles