I'm creating a web application specifically targeted for phones (primarily iPhone, but Android & WP are on the horizon...).
One of the screens contains a scrolling list of items. I would like the list to behave similarly to the built-in iOS Mail app.
In other words...
So - it's important to figure out what the user's intention is, which means I probably need to prevent ANY response until I figure out whether the user is moving her finger vertically or horizontally.
By simply setting these CSS styles on the list container...
overflow-y: auto;
-webkit-overflow-scrolling: touch;
... I get #1 & #2 above. So, I need to figure out how implement #3.
My first thought was to implement something like this (pseudocode)...
touchstart
event listener on the list container. In the callback, store the x- and y-coordinates of the user's starting touch position.touchmove
event listener on the list container. In the callback, figure out how far the user's finger has moved (e.g., delta_x and delta_y)I expected that I would use event.preventDefault() in either the touchstart
or touchmove
to control when scrolling should begin. E.g.,
div.addEventListener("touchstart", function(e) {
touchStart = {
x: e.touches[0].pageX,
y: e.touches[0].pageY
}
}, false);
div.addEventListener("touchmove", function(e) {
touchNow = {
x: e.touches[0].pageX,
y: e.touches[0].pageY
}
var
dx = touchStart.x - touchNow.x,
dy = touchStart.y - touchNow.y;
if ((Math.abs(dx) < 10) && (Math.abs(dy) < 10)) {
// prevent scrolling
e.preventDefault();
} else if (Math.abs(dx) > Math.abs(dy) < 10) {
// moving right/left - slide item
} else {
// moving up/down - allow scrolling
}
}, false);
However - this doesn't work. Regardless of how far you move, the list NEVER scrolls.
Obviously - I'm misunderstanding what triggers the scrolling, and what event.preventDefault() is supposed to do in this context.
So - is there a way to accomplish what I'm after?
I'm hoping for a pure JavaScript solution (so I understand it better), but a jQuery approach would be fine to. I'm definitely hoping to avoid a jQuery plugin/library/framework if at all possible...
Thanks in advance!
I don't suggest reinventing the wheel. There are a number of libraries out there that supports gesture detection. Out of which, I suggest using Hammer.js to detect the touch events.
It doesn't have any dependencies, and it's small, only 3.96 kB minified + gzipped!
And it is all about handling touch events, nothing else.
In your case, Hammer has inbuilt swipe
detection.
You can customize the default swipe gesture by specifying :
velocity : Minimal velocity required before recognizing (unit is in px per ms)
and more.
Following is a simple example (Stack Snippet seems to have some issue emulating touch events, fiddle works fine):
var myElement = document.getElementById("container");
var hammertime = new Hammer(myElement, {});
hammertime.get('swipe').set({
direction: 2 // 2 stands for left
})
hammertime.on('swipe', function(event) {
event.target.querySelector(".delete").classList.add("show");
});
* {
margin: 0;
padding: 0;
}
#container {
width: 250px;
height: 300px;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
background: dodgerblue;
}
#list {
height: 100%;
list-style: none;
}
#list li {
position: relative;
box-sizing: border-box;
width: 100%;
height: 50px;
border: 2px solid #fff;
}
#list li span.delete {
display: inline-block;
position: absolute;
left: 250px;
width: 50px;
height: 40px;
line-height: 40px;
margin: 3px;
text-align: center;
background: #fff;
transition: left 0.5s ease-in;
}
#list li span.delete.show {
left: 170px;
}
<script src="http://cdn.jsdelivr.net/hammerjs/2.0.4/hammer.min.js"></script>
<div id="container">
<ul id="list">
<li class="item"><span class="delete">×</span>
</li>
<li class="item"><span class="delete">×</span>
</li>
<li class="item"><span class="delete">×</span>
</li>
<li class="item"><span class="delete">×</span>
</li>
<li class="item"><span class="delete">×</span>
</li>
<li class="item"><span class="delete">×</span>
</li>
<li class="item"><span class="delete">×</span>
</li>
<li class="item"><span class="delete">×</span>
</li>
<li class="item"><span class="delete">×</span>
</li>
<li class="item"><span class="delete">×</span>
</li>
</ul>
</div>
If you are more interested in learning how the touch event works rather than getting the job done , then I suggest looking under the hood of Hammer.
There is a little Hammer.js jQuery plugin as well, for those who can't part with jQuery.