Handling Touch Events - onInterceptTouchEvent and onTouchEvent
Note that onInterceptTouchEvent()
is a method from the ViewGroup
class, and not from Activity
.
You can achieve the desired behavior by moving your logic from onInterceptTouchEvent()
to dispatchTouchEvent(MotionEvent ev)
. Remember to call the superclass implementation of dispatchTouchEvent(MotionEvent ev)
to handle the events that should be handled normally.
Also note that you should consider a movement to be a swipe only when the delta is bigger than the system constant for touch slop. And I suggest making sure that the user is swiping in the direction you want by testing yDelta / 2 > xDelta
instead of yDelta > xDelta
.
public class Game extends Activity {
private int mSlop;
private float mDownX;
private float mDownY;
private boolean mSwiping;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.game_activity);
ViewConfiguration vc = ViewConfiguration.get(this)
mSlop = vc.getScaledTouchSlop();
//other code....
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
mDownX = ev.getX();
mDownY = ev.getY();
mSwiping = false;
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
if(mSwiping) {
swipeScreen(); //if action recognized as swipe then swipe
}
break;
case MotionEvent.ACTION_MOVE:
float x = ev.getX();
float y = ev.getY();
float xDelta = Math.abs(x - mDownX);
float yDelta = Math.abs(y - mDownY);
if (yDelta > mSlop && yDelta / 2 > xDelta) {
mSwiping = true;
return true;
}
break;
}
return super.dispatchTouchEvent(ev);
}
}
One touch in dispatchTouchEvent registered multiple times
When using dispatchTouchEvent , you take all touches in your activity, if you want only detect one touch, you have to filter the touch by its type, you can do this using the MotionEvent parameter.
if( ev.getAction() == MotionEvent.ACTION_UP){
//launch activity video player
}
How are Android touch events delivered?
From Activity viewpoint:
Touch events are delivered first to Activity.dispatchTouchEvent. It's where you may catch them first.
Here they get dispatched to Window, where they traverse View hierarchy, in such order that Widgets that are drawn last (on top of other widgets) have chance to process touch in View.onTouchEvent first. If some View returns true in onTouchEvent, then traversal stops and other Views don't receive touch event.
Finally, if no View consumes touch, it's delivered to Activity.onTouchEvent.
That's all your control. And it's logical that what you see drawn on top of something else, has chance to process touch event before something drawn below it.
How to use dispatchTouchEvent?
You can try calling yourView.dispatchTouchEvent(MotionEvent.obtain);
Custom dispatchTouchEvent causes View.OnClickListener to be ignored
Problem was not having my detail view inserted in ViewGroup. When mDetailView became child of my custom ViewGroup, problem was solved.
Android onInterceptTouchEvent doesn't get action when have child view
The solution relates to this answer, as it is a result of the standard MotionEvent
handling.
In my code, when I touch the child LinearLayout
, the parent CustomViewGroup
doesn't intercept the MotionEvent
as it returns false, but my child LinearLayout
doesn't consume the MotionEvent
either, so the MotionEvent
is returned to the parent's onTouchEvent
, not onInterceptTouchEvent
.
On the other hand, when I touch my child ScrollView
, it consumes the MotionEvent
whether scrolling is enabled or disabled.
==> I think because Android doesn't generate a MotionEvent
again until the original one is either consumed or finished, so the parent CustomViewGroup
doesn't get the ACTION_MOVE
MotionEvent
via onInterceptTouchEvent
, instaed it is piped to onTouchEvent
when a child doesn't consume the MotionEvent
.
I found two solutions
Solution one
Forcibly make my LinearLayout
consume the MotionEvent
. This solution is available only when the child LinearLayout
has no touchable View
, ViewGroup
or Widget
. Like this:
LinearLayout mLinearLayout = (LinearLayout)findViewById(R.id.child_linear);
mLinearLayout.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return true;
}
});
Solution two
Process the MotionEvent
returning from a child in my CustomViewGroup
's onTouchEvent
. Like this: (Just add else if case in onTouchEvent
).
case MotionEvent.ACTION_MOVE: {
if (mIsBeingDragged) {
mLastMotionY = event.getY();
mLastMotionX = event.getX();
pullEvent();
return true;
}
else if (isReadyForPull()) {
final float y = event.getY(), x = event.getX();
final float diff, oppositeDiff, absDiff;
diff = y - mLastMotionY;
oppositeDiff = x - mLastMotionX;
absDiff = Math.abs(diff);
ViewConfiguration config = ViewConfiguration.get(getContext());
if (absDiff > config.getScaledTouchSlop() && absDiff >
Math.abs(oppositeDiff) && diff >= 1f) {
mLastMotionY = y;
mLastMotionX = x;
mIsBeingDragged = true;
}
}
break;
}
While solution 1 is a quick fix for certain situations, solution two is the most flexible and reliable.
Android-dispatchTouchEvent is not catching ACTION_CANCEL
@pskink's answer is correct. i.e. ACTION_CANCEL is a system event.
"ACTION_CANCEL occurs when the parent takes possession of the motion, for example when the user has dragged enough across a list view that it will start scrolling instead of letting you press the buttons inside of i.
http://developer.android.com/reference/android/view/ViewGroup.html#onInterceptTouchEvent%28android.view.MotionEvent%29
Related Topics
Spring Security Does Not Allow CSS or Js Resources to Be Loaded
Android Recyclerview Addition & Removal of Items
Android Getting Value from Selected Radiobutton
How to Group a 3X3 Grid of Radio Buttons
Java Is Installed, in Listing, But Execution Produces "./Java: No Such File or Directory"
Execute a Linux Terminal Command in Java
Using Visualvm to Connect to a Remote Jstatd Instance Through a Firewall
Commons Vfs and Java.Net.Url - Adding Support for "Sftp://" Protocol
How to Change a Jfreechart'S Size
How to Unzip Files Programmatically in Android
Couldn't Install Netbeans 11.3 with Java 14 Due to Error: "Unsupported Jvm Version"