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.
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
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;
}
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..?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With