25

Imagine a layout with 4 buttons

 _______________________________
|              |                |
|      A       |       B        |
|______________|________________|
|              |                |
|      C       |       D        |
|______________|________________|

I'd like to detect the fling gesture over the whole layout but when the fling starts over a button is no detected.

I'm using:

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    gesturedetector= new GestureDetector(this, this);

    findViewById(R.id.touchContainer).setOnTouchListener(new OnTouchListener() {

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            Log.e("","TouchEvent");
            return gesturedetector.onTouchEvent(event);
        }
    });
}

It when there is no clickable items but fails if the fling start over a clickable item.

How can I solve that? Offering a bounty of 50 point for a complete working answer

Addev
  • 31,819
  • 51
  • 183
  • 302
  • 2
    `Will give 50 point as reward to a complete working answer` is called "offering a bounty", a concept long implemented by StackExchange sites. See this FAQ section: http://stackoverflow.com/faq#bounty – Paul Sasik Feb 07 '12 at 18:15
  • lol. Only that you will definitely need to set a bounty on this question and you may want top offer up more than 50 rep. Why? I think that the answer will most likely be a custom swipe detector that works across multiple controls... – Paul Sasik Feb 07 '12 at 18:28
  • The page says "question eligible for bounty in 2 days" so as soon as I can I'll open the bounty and assign it to an answer. Of course if there is no an easy answer I'll pay more there is no problem – Addev Feb 07 '12 at 18:34
  • Actually, just got an idea... I'm not that familiar with Android UI but on other platforms I would overlay a transparent panel over the buttons. The panel would handle all events where swipes would be handled one way and clicks would be translated to button presses for the buttons in the grid "underneath" – Paul Sasik Feb 07 '12 at 19:01
  • @Addev: How did you solved the problem? Please share the code. Thanks – user1090751 Mar 10 '20 at 06:04

1 Answers1

28

One way I have achieved this is to override the following method:

public boolean onInterceptTouchEvent(MotionEvent event){
    super.onInterceptTouchEvent(event);
    ...

You can override this method in your layout container (e.g. ViewGroup, or whatever you're holding the buttons with) and continue to return false from it in order to 'intercept' touch events that are being consumed by child Views (i.e. your buttons). Within that overridden method you can then call your gesture detector object with the MotionEvents. This method also 'sees' events that target the ViewGroup itself as well, which means - if I remember correctly - you would only need to call your gesture detector from within that method, and in doing so the gesture detector will 'see' all events, no matter whether they'er over the buttons or not. So if you drag your finger starting over a button and then ending at some point on the layout background, the gesture detector should see the entire swipe. You would not need to feed the gesture detector with the events from the layout's own onTouchEvent() because it'll have already seen them.

A second way:

I just looked at my project where I used this, and realised that I switched to a different way of doing it. What I actually did was I designed all of my child Views such that the parent Activity (or the containing ViewGroup) could register the same gesture detector object with all of those child Views (each of my special Views have a method called registerGestureDetector()). Then, in the overridden 'onTouchEvent()' in my child Views, I pass the MotionEvents to the gesture detector that has been registered with that View. In other words, the parent ViewGroup layout and all the child Views simply share the same gesture detector.

I realise that this may sound like a bit of hassle and not necessary considering it could be done using onInterceptTouchEvent(), but my application deals with some pretty complicated rules regarding how my Views need to respond to touch events and gestures, and it allowed me to apply some additional logic that I needed specific for my application. However, both of these methods I've used achieve the same basic objective here: to channel the MotionEvents that targetted various Views to the same gesture detector object.

Trevor
  • 10,903
  • 5
  • 61
  • 84
  • Thanks a lot for your answer, just testing but both answers seems to work! =). Giving the bounty ASAP – Addev Feb 07 '12 at 19:17
  • supposedly, [splitMotionEvents](http://developer.android.com/reference/android/view/ViewGroup.html#attr_android:splitMotionEvents) should enable this automatically if set true on the parent 'ViewGroup'. but it does not happen. Maybe a bug? Documentation is ambiguous though with wording like "may" and not specifying what happens when a touch event happen on both views simultaneously (both UP and DOWN) – leRobot Sep 10 '14 at 15:57
  • I am using custom calendar in my code and i want to swipe the calendar using fling. but it is not working on CalendarView with onInterceptTouchEvent. Can you share your code of onInterceptTouchEvent? – Rakesh Dec 28 '16 at 13:27
  • @Trevor: Any link to example or tutorial using the first approach? Thanks. – user1090751 Mar 26 '20 at 13:06