I would like to add some multitouch features to my javascript application when it is accessed from an ios device (and maybe android later).
I want to provide a shiftkey-like functionality: the user may hold a button on the screen with one finger, and while this button is pressed, the behavior for a tap action on the rest of the screen is slightly different from the classic tap.
The problem i'm running into is that i do not receive any touchend event for the tapping finger unless a touchmove is fired for the first finger holding the shiftkey button.
Because the screen is very sensitive, touchmove events gets easily fired and in most cases everything works fine.
But when the user's finger is a bit too still, the tapping is not detected until the user moves his finger a bit.
This induces a variable 'delay' between the tapping and the action that occurs on the screen (the delay may vary and last a few seconds if the user is very calm).
My guess is that this delay will cause the user to tap again and thus fire the action a second time, which is something that i don't want !
You can test it here with your ipad/iphone : http://jsfiddle.net/jdeXH/8/
Try to make the body remain green for a few seconds by holding your finger very still on the cyan div while tapping on the red div.
Is this behavior to be expected ?
Is there some known workaround for the problem ?
I would have expected the touchend event to be fired right away when the finger is removed from the screen.
i tested this with iOS 5.1.1 (ipad1 and iphone4s)
edit: found a similar question Multitouch touchEvents not triggered as they should on Safari Mobile
Well, it appears that the bug bothered some people more than me, they filed a bug directly to apple, and after a few years it is now fixed in iOS6 :)
Okay this is a headache. Yes, there are two known issues. First of all, Safari sometimes doesn't bother firing the touchEnd event unless there is a touchMove somewhere, even if the touchMove doesn't really do much.
second, Chrome Mobile is a lovely experience as well, as on many Android devices the touchEnd event does not fire at all, regardless of what you do. So from my experience:
- Implement a touchStart event which registers the start coordinate, etc
- Implmenet a touchMove event which does the exact same thing as the touchEnd, but make sure the callback doesn't fire more than once. Use a boolean flag defined in a higher scope or something like that.
- Implement the normal touchEnd event which should only fire if touchMove hasn't already fired the callback, using the same boolean flag defined in a higher scope.
Ok, I have implemented this solution and it seems to work.
//Initialize the tap touch
function ManageTapTouch() {
this.__enabled__ = false;
}
ManageTapTouch.prototype.init = function(){
$("#hold").bind('touchstart', $.proxy(this.__enable__, this));
$('#hold').bind('touchend', $.proxy(this.__disable__, this));
$('#tap').bind('touchstart', $.proxy(this.__changeColorOnHold__, this));
$('#tap').bind('touchend', $.proxy(this.__changeColorOnOut__, this));
};
ManageTapTouch.prototype.__enable__ = function(event) {
this.__enabled__ = true;
};
ManageTapTouch.prototype.__disable__ = function(event) {
this.__enabled__ = false;
$('body').css('background-color', 'blue');
};
ManageTapTouch.prototype.__changeColorOnHold__ = function(event) {
if (this.__enabled__){
$('body').css('background-color', 'black');
}
};
ManageTapTouch.prototype.__changeColorOnOut__ = function(event) {
$('body').css('background-color', 'blue');
};
new ManageTapTouch().init();
You can see it running here: http://jsfiddle.net/Tb6t6/15/
Also you can try another way on the iPhone using multitouch with: event.originalEvent.touches[0].pageX
and event.originalEvent.touches[0].pageY
where the index is the finger on the screen and event is the event fired on TouchStart
. With this topics you can implement your own version of this action or use the one I propose here.
So it appears you have reached one of those scenarios which cannot be avoided and will only have buggy hacks. You are creating a UI feature which is not quite the "norm" yet, but seems to have some promise (I like... I like). The question to ask yourself at this point in technology is "how can I force the user to slide his finger in order to hold shift".
With the help of a good designer I think you could create a sliding toggle button similar to a flip switch... where a user must drag and hold to turn the switch "on". Upon release, the switch would spring back to the "off" position. I mention a designer because the button needs to look like it behaves. Maybe some of the comments can get creative.