hammerjs / hammer.js

A javascript library for multi-touch gestures :// You can touch this
http://hammerjs.github.io
MIT License
24.12k stars 2.63k forks source link

Hammer.js makes -webkit-overflow-scrolling: touch buggy on iOS #250

Closed matt-curtis closed 9 years ago

matt-curtis commented 11 years ago

When using Hammer.js on element inside of a container with -webkit-overflow-scrolling: touch on it, scrolling got jumpy and less smooth.

I observed this simply when calling Hammer(element), without any of my own code.

For now I've solved it by just stripping out Hammer.js and creating my own touch handling, but I'm still submitting this issue (although I didn't see it mentioned before).

Note: It's also worthwhile I think, for Hammer.js to check and make sure the parent container's scrollTop hasn't changed between touchstart and touchmove/touchend, to be sure of whether or not it's a scroll event (iOS doesn't provide a live scroll event for native scrolling) - this was a huge help in my code.

tim-peterson commented 11 years ago

@matt-curtis I'm having the same issues with scrolling, would you mind sharing your code to see how you've solved the problem?

matt-curtis commented 11 years ago

@tim-peterson I've mostly moved completely away from using Hammer.js and webkit scrolling, but it was along these lines:

var touchData = {};

$(element).on("touchstart", function(){
    var scrollBox = $(this).parents(".scrollContainer").eq(0);

    touchData.scrollTop = scrollBox.scrollTop();
});

//or $(element).on("tap", function(){
$(element).on("touchend", function(){
    var scrollBox = $(this).parents(".scrollContainer").eq(0);

    if(touchData.scrollTop != scrollBox.scrollTop()) return; //Scroll event, don't do whatever comes after this
});

But, I should mention that I never totally got rid of these issues. Certain types of Hammer.js event handlers caused more issues than other, simpler ones, like "tap", etc. I'd experiment with that, and see which ones cause the least issues. You'd also want to set 'stop_browser_behavior': false in your Hammer.js settings object.

jinder commented 11 years ago

I'm also seeing this behaviour and have had to disable hammer.js on any elements that use -webkit-overflow-scrolling: touch;.

jtangelder commented 10 years ago

Issuebot: This issue is auto-closed because it's last activity was too long ago. If you think the issue is still active, please re-open it!

jinder commented 10 years ago

Can this be reopened - it's still an issue with the latest hammer.js

baluubas commented 10 years ago

I having this issue as well. Saw that FastClick implemented a workaround for this about a year if that helps: https://github.com/ftlabs/fastclick/issues/42

arschmitz commented 9 years ago

Is this still an issue with v2 and with newer iOS versions i know overflow touch used to be pretty buggy in old versions but is much more stable now. This also looks like it was v1 Im going to close this for now but if its still an issue with latest code comment and we will re open.

clauderic commented 9 years ago

I believe this is still an issue. It works fine if you only have a panh listener, but the moment you add a panv listener (even if the panv listener is only to require failure of panh), overflow-scrolling stops working

runspired commented 9 years ago

@clauderic that's intended and well documented behavior, you can use vertical touch-action and scroll, if you need vertical touch-action in a scrollable area you'll need to implement your own scroller.

It also doesn't make sense from a UX perspective to allow vertical gestures and vertical scroll or horizontal gestures and horizontal scroll in the same region.

clauderic commented 9 years ago

Perhaps I didn't document my issue well enough, this is the setup I currently have:

var hammer = new Hammer.Manager(this.el, {
    recognizers: [
        [Hammer.Pan, {event: 'panv', direction: Hammer.DIRECTION_VERTICAL}],
        [Hammer.Pan, {event: 'panh', direction: Hammer.DIRECTION_HORIZONTAL, threshold: 10}, null, ['panv']]
    ]
});
hammer.on('panhmove', Hammer.bindFn(this.onPanHMove, this));
hammer.on('panhend', Hammer.bindFn(this.onPanHEnd, this));

I have an element that I want to be draggable horizontally (a sidebar drawer), but I want the listener to fail if the original touch is a vertical swipe (because I want the contents of the sidebar to be scrollable vertically). That said, the moment I add the panv recognizer, even if it isn't linked to any listeners, overflow-y: scroll and -webkit-overflow-scrolling stop working entirely in iOS safari, and the contents of the sidebar are no longer scrollable. The code works fine in Chrome.

If I remove the panv recognizer, overflow-scrolling behaves as expected.

I believe this is a bug, unless I'm doing something wrong, as I'm trying to have horizontal gestures and vertical scroll (i.e., not in the same direction as you mentioned).

I've tried setting domEvents: true, but to no avail

clauderic commented 9 years ago

For now, the only way I've managed to solve this is by removing the 'panv' recognizer and listening to the hammer.input event in order to keep track of the original event.direction on panhstart and ensuring it is equal to Hammer.DIRECTION_LEFT in the onPanHMove logic.

runspired commented 9 years ago

I've managed to solve this is by removing the 'panv' recognizer

Correct, as I stated above you cannot have vertical scrolling and a vertical pan/swipe or rotate/pinch at the same time. This is well documented and intentional.

hammer.on('panhmove', Hammer.bindFn(this.onPanHMove, this)); and ensuring it is equal to Hammer.DIRECTION_LEFT in the onPanHMove logic.

Why not just use panhleft ?

clauderic commented 9 years ago

The thing is, there is no code linked to the panv recognizer, it was only in place to call the requireFailure functionality. The idea isn't to have vertical pan/swipe functionality, it's only to have a test of whether the original touch direction was horizontal. Perhaps this should be a feature...?

Sure, I can use panhleft, but that still doesn't solve the problem of ensuring the original touchmove's direction is towards the left. If the original touch is vertical and the user then changes the direction to the left, the recognizer will be triggered.

runspired commented 9 years ago

there is no code linked to the panv recognizer

None of your code, sure, but the recognizer itself is what can't exist along with vertical scroll.

If the original touch is vertical and the user then changes the direction to the left, the recognizer will be triggered.

This is something that's on you to detect, and would be quite simple to do. Cache the scroll top on panstart, and compare the vertical scroll value during panleft.

clauderic commented 9 years ago

Right but you can't hook in to the panstart event without a general pan recognizer, I can only hook in to the panh recognizer in my case, which does me no good, because it's the panv events I want to filter out. And the instant you put a recognizer on either pan or panv, overflow-scrolling stops working on iOS, which is also no good. So the only way is to tap in to the hammer.input event but that's overly complex for no reason

runspired commented 9 years ago

This is doable quite easily without hacks. In my own app I have a long scrollable list and each item can be panned left or right.

glomotion commented 9 years ago

Hi there,

I'm currently trying to get around an issue which feels like it might be related...

Codepen > http://s.codepen.io/glomotion/debug/NqeMvE

Essentially, I want to be able to use hammer simply to detect start and end of any pan event (or at the very least all pan-x events), whilst still allowing natural overflow-scrolling on the x-axis. A touchAction declaration on the pan recogniser allows this to work just fine on Android > Chrome, but not on iOS > Safari. For now, I'm not too concerned about iOS > Chrome.

Is there a reliable way to detect all directions (or just x) of pan movement, but also allow normal overflow scroll-x behaviour (in iOS)? I have tried switching the pan recogniser to vertical, but found that the panstarts aren't always / reliably detected straight away.

Am I doing something wrong with the setup?

thejae commented 8 years ago

Just came across this issue today. It's no big deal in my case, I can bind hammerjs to a parent DOM avoiding the child with touch overscroll property.

Note. The funny thing is that this happen in Safari iOS only but no problem on Google Chrome for iOS.

Would be great if this was documented as a known issue.

runspired commented 8 years ago

@thejae it is documented as a known issue, unfortunately people don't know what to look for. This is a meta issue of needing docs for the documentation ;)

runspired commented 8 years ago

Documentation Link: http://hammerjs.github.io/touch-action/