9

Is it possibile to detect if an element has stopped scrolling in Mobile Safari via Javascript?

I have an element that has momentum scrolling by using -webkit-overflow-scrolling:touch, and I need to detect if the element has stopped scrolling, including after the momentum affects the scroll.

Is this possible? Using the onscroll event is not working as it should within my app.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Charlie
  • 11,380
  • 19
  • 83
  • 138

3 Answers3

7

You can calculate a swipe velocity and try to figure out if momentum scroll will occur based on some threshold value. I've done some testing and about 0.25 pixels/ms seems to be a good value.

Note: Sometimes momentum scrolling will occur for lower velocities too. The lowest velocity to cause momentum scrolling that I recorded was 0.13 (with very short delta time) so if you need a 100% perfect solution, keep on looking.

The example code also detects and deals with overscrolling.

Using JQuery;

var scrollWrapper = $('#myWrapper');
var starTime, startScroll, waitForScrollEvent;
scrollWrapper.bind('touchstart', function() {
   waitForScrollEvent = false;
});

scrollWrapper.bind('touchmove', function() { 
  startTime = new Date().getTime(); startScroll = scrollWrapper.scrollTop();
});

scrollWrapper.bind('touchend', function() {
  var deltaTime = new Date().getTime() - startTime;
  var deltaScroll = Math.abs(startScroll - scrollWrapper.scrollTop());
  if (deltaScroll/deltaTime>0.25 
        || scrollWrapper.scrollTop()<0 
        || scrollWrapper.scrollTop()>scrollWrapper.height()) {
    // will cause momentum scroll, wait for 'scroll' event
    waitForScrollEvent = true;
  }
  else {
    onScrollCompleted(); // assume no momentum scroll was initiated
  }
  startTime = 0;
});

scrollWrapper.bind('scroll', function() {
  if (waitForScrollEvent) {
    onScrollCompleted();
  }
});
kfb
  • 6,252
  • 6
  • 40
  • 51
dagge
  • 1,145
  • 9
  • 13
  • This is fantastic! I've been struggling making an internal div scrollable, and by enabling the momentum, all snap logic I had went out the window. You are missing a couple commas and the wrapper variable isn't defined. Otherwise it's great! – Chris May 15 '14 at 21:36
  • Glad you've found it useful. Thanks for pointing out the errors. – dagge May 17 '14 at 08:22
  • very nice. make a demo for it. it could be useful for others to check the result quickly – iraj jelodari Nov 07 '17 at 17:56
  • I don't get it, you just listen to the first scroll event. When momentum scrolling happens it keeps emitting scroll events till the end. Proper answer is below. – waterplea Feb 08 '19 at 07:09
  • This was a long time ago. I believe that the gist of the problem was that on Mobile Safari, no scroll events were emitted during momentum scrolling. That was what the above code tried to solve. Perhaps that has since changed. – dagge Feb 08 '19 at 16:35
5

In my case this worked perfectly:

var timer;
$(scrollWrapper).on('scroll',function(e){
    if(timer){
        clearTimeout(timer);
    }
    timer = setTimeout(function(){
       $(this).trigger('scrollFinished');
    }, 55)
})



 $(scrollWrapper).on('scrollFinished',function(){
         // will be called when momentum scroll is finished
   })

Publish 'scrollfinished' event when scroll has stopped.

rishabh dev
  • 1,711
  • 1
  • 15
  • 26
  • 1
    Interesting technique, for some particular use cases it can be even better than the accepted answer (as it was in my case). +1 – Teodor Sandu Mar 22 '16 at 12:55
  • Great simple solution, I had to tweak the timeOut length to a larger number though – Arjan Jan 06 '18 at 11:06
0

You could also add a function that recursivly calls itself until the scrolling has stopped within the element and then call futher function from there.

isScrolling() {
  var scrollStart = <element>.scrollTop;
  setTimeout(function() {
    var scrollPos = <element>.scrollTop;
    if (scrollStart !== scrollPos) {
      this.isScrolling()
    } else {
      // Scrolling has stopped
    }
  }, 100)
}
tjaydk
  • 281
  • 3
  • 8