If you’ve used an iOS device you’ve seen lists that you can touch scroll and then tap to select an item on the list. I wanted to reproduce that native behavior with web coding. But the web site would be accessible to more than just iOS devices.
The first way I got this to work was before I had to add “default prevention” to get the site to work properly on Android. So, without default prevention I could rely on the mouse event firing about 300 milliseconds after the touch event on an object. I could also rely on those mouse events being canceled if I was in the midst of a touchmove event. This worked brilliantly, and exactly like it does in the native UI of both iOS and Android.
But once I HAD to add default prevention for Android (to prevent it from firing mouse events 300ms after touch events on other elements) I couldn’t get the tap-to-select scrolling list to work right on that platform anymore. If I used a touchstart event as soon as you put a finger down to scroll the list it would select the list item you’d put your finger on. If I used touchend then it would trigger whichever list item was the last one you touched.
That was how I got off on the tangent of selective default prevention and restoration. Which worked, except for the unwanted double click requirement and extra code to restore the default prevention afterwards.
There is a lengthy and not very helpful post on the Android Dev site describing how to make a web app employ native momentum scrolling, which also includes “ghost click” prevention to ignore taps intended as part of a touchmove event. But it gets very complicated in checking the distance of a move in pageY, etc. I had already tried and dismissed something similar where I added a calculation to my touchmove event to determine if and how far it had moved in pageY and how many seconds had elapsed (which required tagging touch events with a timestamp). It proved too much for the mobile webkit browsers, both of which would crash after a couple of touch scrolls. The Google dev’s method utilizes 3D transitions for scrolling to leverage hardware acceleration, which is probably why their method can handle the math.
At this point I’ll say that I’m not a big fan of momentum scrolling in the first place. I absolutely HATE it when I’m touch scrolling through something and it goes flying off further than I intended and I have to stop it with a tap like it’s a whirling top. We generally don’t have this momentum behavior on desktop machines with scrolling, I don’t know why anyone thought it was a good idea on a touch device other than it looks kind of cool, but I’m convinced it’s a bad UI behavior.
After I slept on the problem I realized that what I was REALLY after was something incredibly simple. My list items trigger on a desktop with “mouseup” because I knew (without default prevention) that is the corollary to “touchend” on a mobile device. I knew touchend was what I wanted because I had no way of knowing if a touchstart was going to be followed by a touchmove (for scrolling) or not (for item selection). Which meant that what I wanted to know was if the “touchend” event was preceded by a touchmove or just a touchstart.
So I created a namespaced variable called “touchmoveCheck” and set it to zero as a default (meaning no touchmove had taken place). Then, in my touch scrolling function I added “touchmoveCheck=1” and on my list item’s touchend event have it do a “tap check” where it first looks for that variable and if it is set at 1 it does nothing, because obviously the touchend event is the end of a touchmove. If the value is zero, though, I know the touchend is the end of a touchstart without a touchmove, and so I trigger my mouseup event. The parent container for the list (which can be either a DIV or the UL) just needs to set touchmoveCheck to zero on touchstart so we know it is a new touch sequence.
Works PERFECTLY! And it’s not a lot of code or math so it’s still very responsive, even without hardware acceleration.