I have a parent, custom RelativeLayout which inflates two ImageViews: one content image, and a close button in the top right corner.
The issue: I cannot have both the gestures/scaling of the content image functioning AND the close button functioning.
The content image is a custom ImageView subclass (a modification of https://github.com/MikeOrtiz/TouchImageView), which has it's own OnTouchListener to allow for pinch-zooming, and responding to usual gestures.
This OnTouchListener contains the code:
private class PrivateOnTouchListener implements OnTouchListener {
#Override
public boolean onTouch(View v, MotionEvent event) {
mScaleDetector.onTouchEvent(event);
mGestureDetector.onTouchEvent(event);
//....
return true;
Now, if that return is true, the scaling/gestures for the content image works, but the close button onClick is never called, whereas if it's false then the scaling/getures don't work and the onClick can be called.
I don't understand why a return function called AFTER the event is passed to the gesture detector affects (?consumes the event) whether or not the gesture detector works.
Is there a simple way of ensuring the functionality of both child ImageViews, where that return function is false but both detectors still work?
What I've tried:
Ensuring all methods in the gestureDetector return false, so that the event isn't consumed. (The scaleDetector isn't custom, so I haven't done the same there; if you think that's where the problem is let me know)
An onInterceptTouch method in the parent RelativeLayout, but I'm not sure if I implemented that correctly
(Reading around event handling to understand how it works)
Related
I am overriding dispatchTouchEvent() method to detect each and every touch in an activity.
#Override
public boolean dispatchTouchEvent(MotionEvent event) {
System.out.println("android test "+event.toString());
return super.dispatchTouchEvent(event);
}
But this method is catching only ACTION_UP,ACTION_DOWN and ACTION_MOVE events,not ACTION_CANCEL event. What may be the reason for this ?
#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
I have a ViewPager that can contain two types of views. One of the view types has buttons, one of the view types does not. The buttonless view type does have to trap touches in onTouchEvent in order to pan and zoom an image. But I want to let clicks bubble to the ViewPager (that has a clickListener attached to it)
I have to return true in the view's onTouchEvent ACTION_DOWN or else it won't see future events.
I can't use onInterceptTouchEvent() in the ViewPager to capture clicks because one of the views does have buttons and those buttons need their clicks
So how can my view trap swipes, and let clicks bubble up?
proper way is probably to intercept only the events you want to intercept, by returning true in onInterceptTouchEvent only when needed.
but if you want to go with the dark side, there's a dirty alternative, that probably will lure you and you'll probably regret later: intercept all the events, then if needed pass them down.
e.g. have inside your views something like
public boolean canInterceptTouch(MotionEvent ev) {
// return true if you are interested in this touch event, e.g. it falls into
// a clickable area
}
and something that handle the touch event like
public void interceptTouch(MotionEvent ev) {
// here you react to the event
}
inside your viewpager you have
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return true;
}
thien the view pager will handle the events in a dirty way like this:
#Override
public boolean onTouchEvent(MotionEvent ev) {
if (yourView.canInterceptTouch(ev))) {
yourView.interceptTouch(ev);
return true;
} else {
return doSomethingElse();
}
}
note: although I've done something similar, with decent result, I do NOT reccomend it as a solution unless you've very simple logic in the handling of the motion events, otherwise it becomes a mess. Your future self will be happier if you spend some time now to do it properly.
EDIT: code has not been tested, just to give you an idea of what you need. Sorry for any typo.
Try using this ViewGroup.onInterceptTouchEvent(MotionEvent).This allows a ViewGroup to watch events as they are dispatched to child Views`
I have a TextView in a fragment where I want to set different texts when the gesture is detected.
#Override
public boolean onTouchEvent(MotionEvent event) {
this.gestureDetector.onTouchEvent(event);
return super.onTouchEvent(event);
}
The above code is used to listen for gesture, but it can only be used in an Activity class somehow, when I put .onTouchEvent() in a fragment class, it says cannot resolve method. Any idea how I can manipulate a view from outside the fragment or any ways to basically listen for the gestures like I did in the Activity class??
You can add touch listeners to views, so get the root view of that fragment, and add your listener with view.setOnTouchListener(...)
I want to get x and y position of every touch point in my activity even in drag mode. When I implement onTouchEvent method of my activity, it does not get all of touch events. How can I do that?
Thanks in advance,
public class MyActivity extends Activity {
#Override
public boolean onTouchEvent(MotionEvent event) {
// my Code
return super.onTouchEvent(event);
}
}
This onTouchEvent method just rises when you touch around the activity.
Do you have any other View which handle touch events?
The documentation says:
Called when a touch screen event was not handled by any of the views
under it. This is most useful to process touch events that happen
outside of your window bounds, where there is no view to receive it.
So when you say you don't get any events when you are in drag mode, this implies that you're dragging some thing. So you already handling the events somewhere else and therefore the onTouchEvent() method won't be notified.
You can try to return false in the other TouchListener's onTouch() method so the event will bubble up further more.
I have a project using a ViewPager which works correctly:
I can page from view to view by flicking left and right.
On one page of the ViewPager, I have a custom view and I am trying to add below it another view (LinearLayout) that is touch sensitive and that will not "page" the ViewPager. Like this:
<LinearLayout >
<myView />
<LinearLayout> // The touch sensitive region
</LinearLayout>
</LinearLayout>
After my view has been inflated and added to the ViewPager, I call setOnTouchListener() to attach a listener to the internal LinearLayout. The listener returns "true".
Unfortunateley when I move horizontally in that view, I move to another page.
The events I get are:
ACTION_DOWN, ACTION_MOVE (n times) and finally ACTION_CANCEL. Although I stayed within the view.
It seems that the event has gone up the view hierarchy and processed by the ViewPager.
Is there a logical explanation to this behaviour ?
I have found a workaround by intercepting events at the Activity level, overriding dispatchTouchEvent().
In there, I call super.dispatchTouchEvent() for processing all events unless the user is touching my touch sensitive view. I test if the user is on the correct page and at the right location. In that case I process the event myself.
#Override
public boolean dispatchTouchEvent (MotionEvent ev) {
if ( pager.getCurrentPosition()!=0 ) { // Test ViewPager page
super.dispatchTouchEvent(ev);
}
else {
int[] xy = new int[2];
findViewById(R.id.myTouchControl).getLocationOnScreen(xy);
int topOfView = xy[1];
if ( ev.getY() > topOfView ) {
// Custom processing
...
} else {
// Standard processing
super.dispatchTouchEvent(ev);
}
}
return false;
}
No need to override dispatchTouchEvent(). Instead, in the ACTION_DOWN event, use View.getParent().requestDisallowInterceptTouchEvent(true).
requestDisallowInterceptTouchEvent(true) requests the parent view (ViewPager) not to intercept this specific touch event. It will clear this flag after the MotionEvent ends, so you must call it in ACTION_DOWN.