Scalegesturedetector.ontouchevent Always Returns 'true'
Solution 1:
Don't know if it's a bug or intentional, but that's definitely what the source does (ScaleGestureDetector.java:156):
publicbooleanonTouchEvent(MotionEvent event) {
finalintaction= event.getAction();
booleanhandled=true;
/* ... bunch of code that never updates 'handled' */return handled;
}
The way I solved this was to check all of the other types of touch events I might want to handle first, then invoke the gesture detector, e.g.
if (mLongPressGestureDetector != null && mLongPressGestureDetector.onTouchEvent(event))
returntrue;
elseif (mIsInMoveMode && mScaleGestureDetector != null) {
// Check for a moveif (action == MotionEvent.ACTION_MOVE && !mScaleGestureDetector.isInProgress()) {
handleMove(event);
returntrue;
}
// Now a scale
mScaleGestureDetector.onTouchEvent(event);
returntrue;
}
Solution 2:
The ScaleGestureDetector provides the method isInProgress() that might do what you want...
Here is an example of it in use:
public boolean onTouch(View v, MotionEvent event) {
mScaleDetector.onTouchEvent(event);
if (!mScaleDetector.isInProgress()) {
if (event.getAction() == MotionEvent.ACTION_DOWN || (event.getAction() == MotionEvent.ACTION_MOVE)) {
touchX = (int) event.getX();
touchY = (int) event.getY();
isTouched = true;
}
if (event.getAction() == MotionEvent.ACTION_UP) {
isTouched = false;
}
} else {
isTouched = false;
}
returntrue;
}
Solution 3:
This is how I solved the problem: By overriding the Acitivity's onDispatchTouchEvent() method. Any other solution seemed not to work. The good thing about the onDispatchTouchEvent() method is that is always called prior to forwarding any touch events to any other receiver, so you can intercept every single touch event here.
If the event is handled somewhere in here (scale or swipe), I return immediately without forwarding the event to the super class, i. e. to the rest of the view hierarchy. If it is not, I forward it to the super class, so other views can handle it, e. g. to detect short or long clicks.
There were a few more problems to solve though: 1. If the user begins a scale gesture, I had to cancel any long click detection processes because the receiving view would get the first DOWN event, then nothing anymore (after the second finger comes down and the scaling started), and then spuriously think that a long press is being performed. 2. When a long press was performed and the context menu came up, I had to prevent swipe and scale gesture detection here in dispatchOnTouchEvent() until the next UP event, otherwise swiping and scaling would be performed even though the context menu is there.
Quite complicated, but I spent hours and hours and a lot of trial and error, and just could not find any simpler solution. Anyway, handling 1. scale gestures, 2. horizontal swipe gestures, 3. vertical scroll gestures, 4. long clicks and 5. short clicks, all on the same target view(s), is not quite simple a mission to accomplish...
Here is the code (relevant parts of it):
@OverridepublicbooleandispatchTouchEvent(MotionEvent e) {
if (eventInProgress) {
// View shall only receive scale gesture event if visibleif (targetView.isShown())
scaleGestureDetector.onTouchEvent(e);
if (scaleGestureDetector.isInProgress())
motionEventConsumed = true;
}
if (motionEventConsumed) {
if (e.getAction() == MotionEvent.ACTION_UP)
motionEventConsumed = false;
if (cancelLongPressEvent) {
cancelLongPressEvent = false;
targetView.cancelLongPress();
}
return (true);
}
// Get the action that was done on this touch eventswitch (e.getAction()) {
caseMotionEvent.ACTION_DOWN: {
// store the X value when the user's finger was pressed down
downXValue = e.getX();
downYValue = e.getY();
cancelLongPressEvent = true;
eventInProgress = true;
break;
}
caseMotionEvent.ACTION_MOVE:
// When having moved by too many x or y pixels, then// cancel any ongoing long klick eventsif (cancelLongPressEvent
&& Math.abs(e.getX() - downXValue)
+ Math.abs(e.getY() - downYValue) > 40) {
targetView.cancelLongPress();
cancelLongPressEvent = false;
}
break;
caseMotionEvent.ACTION_UP: {
if (eventInProgress) {
// Get the X value when the user released his/her finger
float deltaX = e.getX() - downXValue;
float deltaY = e.getY() - downYValue;
if (Math.abs(deltaX) > Math.abs(deltaY)
&& Math.abs(deltaX) > 50) {
// going backwards: pushing stuff to the rightif (deltaX > 0) {
flipRight();
return (true);
}
// going forwards: pushing stuff to the leftif (deltaX < 0) {
flipLeft();
return (true);
}
break;
}
}
}
}
// If event was not handled here, then forward it to parent,// i. e. to view hierarchyreturn (super.dispatchTouchEvent(e));
}
[...]
@OverridepublicvoidonCreateContextMenu(ContextMenu menu, View v,
ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
MenuInflatermi= getMenuInflater();
mi.inflate(R.menu.lztv_context_menu, menu);
contextMenuTargetView = v;
eventInProgress = false;
}
Post a Comment for "Scalegesturedetector.ontouchevent Always Returns 'true'"