onInterceptTouchEvent, onTouchEvent only see ACTION_DOWN
Asked Answered
F

4

7

I have a top level ViewGroup, which I call SliderView, in which I want to detect swiping. This is mostly working, but one weird failure persists.

The essence of SliderView is to override onInterceptTouchEvent and, once the user is actually swiping, return "true" to prevent other views from seing the MotionEvent. Here is a snip of code:

public class SliderView extends ViewGroup
{
  enum MoveState { MS_NONE, MS_HSCROLL, MS_VSCROLL };
  private MoveState moveState = MoveState.MS_NONE;

  ... other code ...

  public boolean onInterceptTouchEvent(MotionEvent e)
  {
    final int action = e.getAction();
    switch (action & MotionEvent.ACTION_MASK)
    {
      case MotionEvent.ACTION_DOWN:
        moveState = MoveState.MS_NONE;
        break;

      case MotionEvent.ACTION_MOVE:
        if (moveState == MoveState.MS_NONE)
        {
          if (motion is horizontal)
          {
            moveState = MoveState.MS_VSCROLL;
            return true;
          }
          else
            moveState = MoveState.MS_VSCROLL; // let child window handl MotionEvent
        }
        else if (moveState == MoveState.MS_HSCROLL)
          return true; // don't let children see motion event.
    }
    return super.onInterceptTouchEvent (e);
  }

  ... other code ...
}

It is my understanding that my SliderView (which is the outermost view) should always recevie onInterceptTouchEvent. In one of my tests, where the top level child is a However, in the following case, this appears not to be.

When the top level child is a ScrollView, onInterceptTouchEvent gets ACTION_MOVE and my code does what I want. In another case, where the top level child is a LinearLayout, it fails sometimes: it always gets ACTION_DOWN but gets ACTION_MOVE only if the user touches a widget inside the LinearLayout; if touching blank area, only ACTION_DOWN comes through.

I'll note that it behaves as if the fail-case touches are happening outside the SliderView. However, if that were the case, why would I get the ACTION_DOWN events?

Second note: looking at the source code for ScrollView, I see it checking for "inChild"; I have not figured out what that's for and how it might be relevant.

Fibula answered 25/9, 2012 at 23:35 Comment(1)
no, but in reading more docs, I learned there is something called ViewPager which incorporates horizontal swiping. I haven't tried it yet as I'm fleshing out other stuff right now. I don't know what you're seeking to do, but if you try ViewPager please let me know the outcome.Fibula
E
6

Due to the answer of user123321 here

onInterceptTouchEvent only get called if the parent has a child view which returns "true" from onTouchEvent. Once the child returns true, the parent now has a chance to intercept that event

Euphonious answered 15/1, 2013 at 6:37 Comment(0)
G
3

All you need is to call

requestDisallowInterceptTouchEvent(true);

on the parent view, like this -

        @Override
        public boolean onTouch(View view, MotionEvent motionEvent) {
            view.getParent().requestDisallowInterceptTouchEvent(true);
            switch(motionEvent.getActio){
            }

            return false; 

         }
Gascon answered 11/1, 2018 at 11:13 Comment(3)
This is probably a right answer but since the question is very old - and my code has long morphed into something else - I won't be able to verify.Fibula
Sorry, I don't understand your question.Fibula
@akshay-sahai Scrolling will stop working If I apply this solution.Kneeland
P
1

From Android developer's reference (http://developer.android.com/reference/android/view/ViewGroup.html#onInterceptTouchEvent(android.view.MotionEvent)):

"2. .... Also, by returning true from onTouchEvent(), you will not receive any following events in onInterceptTouchEvent() and all touch processing must happen in onTouchEvent() like normal."

Maybe because your onTouchEvent always returns true..?

Paiz answered 1/6, 2013 at 4:40 Comment(1)
Actually, it returns "true" for only two cases. The other cases return super.onInterceptTouchEvent ().Fibula
E
0

When intercepting onTouchEvent, there are two things to do to properly intercept the touches (all else being default).

  1. Return false in onInterceptTouchEvent()

    @Override
    public boolean onInterceptTouchEvent(MotionEvent me) {
        return false;
    }
    
  2. Return true in onTouchEvent()

    @Override
    public boolean onTouchEvent(MotionEvent me) {
    
        switch (me.getAction()) {
        case MotionEvent.ACTION_DOWN:
            log("MotionEvent.ACTION_DONE");
            break;
        case MotionEvent.ACTION_MOVE:
            log("MotionEvent.ACTION_MOVE");
            break;
        case MotionEvent.ACTION_CANCEL:
            log("MotionEvent.ACTION_CANCEL");
            userActionDown = false;
            break;
        case MotionEvent.ACTION_UP:
            log("MotionEvent.ACTION_UP");
            break;
        }
    
        return true;
    }
    
  3. Then, for your case (and others). Do all your calculations in the onTouchEvent() as shown above. The onInterceptTouchEvent() will only be called once for the ACTION_DOWN. But, the onTouchEvent will also get the ACTION_DOWN event, and you'll need to return true there, rather than the super.

For more information regarding onInterceptTouchEvent(): http://developer.android.com/reference/android/view/ViewGroup.html#onInterceptTouchEvent(android.view.MotionEvent)

ps - When you ask questions here, you should also write the description of what you are trying to do. You might quite possibly find much better ways of doing things. For your case of navigation, the real answer you are looking for is ViewPager. It works great and is very easy to implement. You should also check out some other easy navigation patters that Android has to offer developers: link.

Eadmund answered 6/9, 2013 at 2:15 Comment(3)
I discovered ViewPager back in November 2012 and stated so above.Fibula
Yes, and that is why I commented on it. You said: I haven't tried it yet as I'm fleshing out other stuff right now. I don't know what you're seeking to do, but if you try ViewPager please let me know the outcome. So, I let you know the outcome because I have used ViewPager. ;) Anymore questions?Eadmund
Yes I tried it and it works very well. Please see #13664655Fibula

© 2022 - 2024 — McMap. All rights reserved.