fljot / Gestouch

Gestouch: multitouch gesture recognition library for Flash (ActionScript) development.
MIT License
356 stars 84 forks source link

Is "canBePreventedByGesture" and "canPreventGesture" actually effect? #19

Closed jane00 closed 11 years ago

jane00 commented 12 years ago

I had a three-finger-gesture with Global stage and an one-finger-gesture with a button or a sprite, but ,when I put one finger on the button and other two fingers outside the button , the three-finger-gesture can not be recognized correctly. why? Thanks very much!

jane00 commented 12 years ago

My English is very poor.Please forgive me.

jane00 commented 12 years ago

And, is "bubble" mechanism possible like AS3 nature MouseEvent? I means that could a gesture event be response by a button and the button's parent at the same time. One event , two or more response.

fljot commented 12 years ago

Yes, canBePreventedByGesture and canPreventGesture should actually work. So you have a custom 3-fingers gesture? With canBePreventedByGesture returns false? Show the gesture code just in case.

There's no bubbling as there's 1) no need 2) no "bubblable environment". You can dispatch your own bubbling event on your DisplayList though, no problems.

jane00 commented 12 years ago

OK, thanks very much.

It's not a custom 3-fingers gesture, just a Swipe gesture that request 3 fingers.

So, this is my purpose: there are 2 gestures active in my stage, 1), 3-fingers SwipeGesture which target is the "stage", request 3 fingers, swipe in 4 directions for different "global" action ; 2), 1-finger SwipeGesture which target is a MovieClip in the "stage", swipe left or right with one finger will trigger some action on the movieclip itself.

So, I want 3-fingers gesture be recognized first.
For example, just like gestures on IPad, "4 finger swipe left or right" is used for switching between different applications, and in an application, 1 finger swipe left may be used for call for "delete" action on an list item.

And,in my code, if there is one finger on the movieclip and other 2 fingers outside the movieclip, "3 fingers swipe right" may not be recognized as the first gesutre "3-fingers SwipeGesture", but the "1-finger SwipeGesture" was recognized.

Fortunately, I solved the problem this afternoon, with some dirty method like this:

I wrote another class "SwipeGesture_TotalTouchSensive" which modify from your "SwipeGesture". In this class, I add some condition judgment like this:

"Gestouch.touchesManager.activeTouchesCount> numTouchesRequired"

so , if total touchs points count is more than 1, the SwipeGesture_TotalTouchSensive fail.

code:

override protected function onTouchBegin(touch:Touch):void { if (touchesCount > numTouchesRequired || Gestouch.touchesManager.activeTouchesCount> numTouchesRequired) { failOrIgnoreTouch(touch); return; }

And the 3-fingers SwipeGesture could be recognized correctly.

Is this the correct way?

fljot commented 12 years ago

Your solution won't work that well actually. Imagine that first (on the screen) touch comes on your object (and therefore in SwipeGesture_TotalTouchSensive) — your condition fails, so everything processed as usual.

Here's what I think about it. I see that this problem consists of two smaller ones.

  1. We want top-level gesture (global, stage swipe) recognition.
  2. We don't want (UI) response to deep-nested gestures. And import thing to note is that these two questions have tight connection.

So what do I mean by first one? Well at the moment top-level swipe could be aborted via deep-nested swipe recognition. So what we can do about it:

  1. Create SwipeGesture subclass where override canBePreventedByGesture method and return false there in some cases (as below) or simply always. This way you ensure your stage multi-finger Swipe won't be aborted(failed) by others.
public class MasterSwipeGesture extends SwipeGesture
{
    override public function canBePreventedByGesture(preventingGesture:Gesture):Boolean
    {
        if (preventingGesture is SwipeGesture &&
            (preventingGesture as SwipeGesture).numTouchesRequired < this.numTouchesRequired)
        {
            // We are more important
            return false;
        }
        return true;//default
    }
}

So your "global action" is fine now. But we still how deep-nested gestures, which might also be triggered at the same time as you perform this global swipe. So 2nd problem is still not solved.

  1. Prevent deep-nested gestures from recognition once certain criteria is met. Criteria in our case is Gestouch.touchesManager.activeTouchesCount or topLevelSwipe.touchesCount. How to prevent from recognition? Either set delegate to those gestures where focus on gestureShouldBegin method - return false if criteria is met. Or extend gestures and carefully override setState method. This way we solve both problems. Not the most elegant way, but it should do the trick.
  2. You could try fancy yet experimental and probably not 100% safe requireGestureToFail API. To do this you must define deepNestedSwipe.requireGestureToFail(topLevelSwipe). It will delay deep-nested swipe recognition a bit to give a chance to top-level one to be recognized. But top-level one will fail either because it was recognized during 500ms due to lack of touches or (even faster) once you lift the finger. And if you perform 3-finger swipe and it recognizes — it will normally abort deep-nested gestures. So it's the solution for both problems.
  3. Slightly re-design interactivity. Ensure that top-level gesture is naturally being recognized first. For example make top-level gesture PanGesture. Normally pan should be recognized earlier than swipe. I believe Apple also uses 4-finger pan gesture (continuous gesture) to switch between applications (it follows your fingers if you do it slowly, right?). This way you also solve both problems as top-level gesture recognizes first and aborts deep-nested ones.

I hope I explained well enough. Tell me if anything is still unclear and/or which way you decide to implement.

Also maybe you see/expect some other solution? I mean some other way that is not technically possible with this library at the moment, but that could be more elegant or simple?

jane00 commented 12 years ago

Firstly,thanks very much for so patiently answering!

I forgot to say that I add the "Gestouch.touchesManager.activeTouchesCount> numTouchesRequired" condition at both "onTouchBegin" and "onTouchMove" funcitons. So, it may works well. As long as the 2nd touch appear before "the 1st touch comes to a swip gesture", the condition will works in "onTouchMove" funcitons, and make the 1-finger SwipeGesture fail as I wish.

My English is poor and my AS3 skill is also not very well, so I could not understand your 3 solutions very well, but I think the 3rd solution is closed to what I want. And I will try it. Thank you again for everything.

ps: If I can upload an attachment somewhere, I'd like to upload my previous dirty solution .apk file and you may see it approximately works fine as I wish.

fljot commented 12 years ago

Yea, if you have that in both onTouchBegin and in onTouchMove it should work as expected. Feels dirty, but does the trick. No need to upload that, I understand my library pretty well and can imagine =)

I still recommend you to try out all the options just to get better with the library if you plan to use it later.

fljot commented 11 years ago

Log: I moved these methods under gestouch_internal namespace so they don't confuse people. These methods are for overriding, not calling.