2011-01-01 29 views
16

Pensé que se suponía que el método "onTouchEvent()" de una instancia "ScaleGestureDetector" devolvería "verdadero" solo si realmente se trata del evento táctil, i. mi. si detecta un gesto de escalamiento multitáctil (con dos dedos). De lo contrario, pensé que se suponía que debía devolver "falso" para permitir que otros manejadores manejaran el evento, e. gramo. una pulsación larga para activar un menú contextual.ScaleGestureDetector.onTouchEvent siempre devuelve 'verdadero'

Observé algo diferente: scaleGestureDetector.onTouchEvent() siempre devuelve "verdadero" en mi caso. El siguiente fragmento de código de mi clase MyView:

public boolean onTouchEvent(MotionEvent event) { 
    boolean retval = scaleGestureDetector.onTouchEvent(event); 
    Log.v("MyView.onTouchEvent()", "Action: " + event.getAction() + 
     "; PointerCount: " + event.getPointerCount() + 
     "; scaleGestureDetector.onTouchEvent() RetVal: " + retval); 
    return(retval); 
} 

produjo la salida del registro follwing después toqué la vista de aproximadamente 1 segundo, con un dedo, luego se realiza un gesto escala con 2 dedos:

01-01 19:09:54.484: VERBOSE/MyView.onTouchEvent()(5930): Action: 0; PointerCount: 1; scaleGestureDetector.onTouchEvent() RetVal: true 
01-01 19:09:54.510: VERBOSE/MyView.onTouchEvent()(5930): Action: 2; PointerCount: 1; scaleGestureDetector.onTouchEvent() RetVal: true 
01-01 19:09:54.541: VERBOSE/MyView.onTouchEvent()(5930): Action: 2; PointerCount: 1; scaleGestureDetector.onTouchEvent() RetVal: true 
01-01 19:09:54.580: VERBOSE/MyView.onTouchEvent()(5930): Action: 2; PointerCount: 1; scaleGestureDetector.onTouchEvent() RetVal: true 
01-01 19:09:54.820: VERBOSE/MyView.onTouchEvent()(5930): Action: 2; PointerCount: 1; scaleGestureDetector.onTouchEvent() RetVal: true 
01-01 19:09:54.910: VERBOSE/MyView.onTouchEvent()(5930): Action: 2; PointerCount: 1; scaleGestureDetector.onTouchEvent() RetVal: true 
01-01 19:09:55.050: VERBOSE/MyView.onTouchEvent()(5930): Action: 2; PointerCount: 1; scaleGestureDetector.onTouchEvent() RetVal: true 
01-01 19:09:55.350: VERBOSE/MyView.onTouchEvent()(5930): Action: 2; PointerCount: 1; scaleGestureDetector.onTouchEvent() RetVal: true 
01-01 19:09:55.400: VERBOSE/MyView.onTouchEvent()(5930): Action: 1; PointerCount: 1; scaleGestureDetector.onTouchEvent() RetVal: true 
01-01 19:09:57.160: INFO/BatteryStatsImpl(96): notePhoneSignalStrengthLocked: 4->3 
01-01 19:10:00.060: ERROR/ClockWidget(215): weatherClock onReceive~ mUseAnimation:false 
01-01 19:10:00.060: ERROR/ClockWidget(215): handleUiMessage~ in pause. msg:36867 
01-01 19:10:00.070: ERROR/ClockWidget(215): weatherClock onReceive~ mUseAnimation:false 
01-01 19:10:00.090: INFO/PI.Alarms(699): Update Alarms start 
01-01 19:10:00.090: INFO/PI.Alarms(699): Task Notifications: Already displaying the same alarms, no update 
01-01 19:10:00.100: INFO/PI.Alarms(699): Event Notifications: Already displaying the same alarms, no update 
01-01 19:10:00.830: VERBOSE/MyView.onTouchEvent()(5930): Action: 0; PointerCount: 1; scaleGestureDetector.onTouchEvent() RetVal: true 
01-01 19:10:00.840: VERBOSE/MyView.onTouchEvent()(5930): Action: 2; PointerCount: 1; scaleGestureDetector.onTouchEvent() RetVal: true 
01-01 19:10:00.870: VERBOSE/MyView.onTouchEvent()(5930): Action: 2; PointerCount: 1; scaleGestureDetector.onTouchEvent() RetVal: true 
01-01 19:10:00.900: VERBOSE/MyView.onTouchEvent()(5930): Action: 2; PointerCount: 1; scaleGestureDetector.onTouchEvent() RetVal: true 
01-01 19:10:00.922: VERBOSE/MyView.onTouchEvent()(5930): Action: 2; PointerCount: 1; scaleGestureDetector.onTouchEvent() RetVal: true 
01-01 19:10:00.931: VERBOSE/MyView.onTouchEvent()(5930): Action: 261; PointerCount: 2; scaleGestureDetector.onTouchEvent() RetVal: true 
01-01 19:10:00.950: VERBOSE/MyView.onTouchEvent()(5930): Action: 2; PointerCount: 2; scaleGestureDetector.onTouchEvent() RetVal: true 
01-01 19:10:01.002: VERBOSE/MyView.onTouchEvent()(5930): Action: 2; PointerCount: 2; scaleGestureDetector.onTouchEvent() RetVal: true 
01-01 19:10:01.030: VERBOSE/MyView.onTouchEvent()(5930): Action: 2; PointerCount: 2; scaleGestureDetector.onTouchEvent() RetVal: true 
01-01 19:10:01.060: VERBOSE/MyView.onTouchEvent()(5930): Action: 2; PointerCount: 2; scaleGestureDetector.onTouchEvent() RetVal: true 
01-01 19:10:01.090: VERBOSE/MyView.onTouchEvent()(5930): Action: 2; PointerCount: 2; scaleGestureDetector.onTouchEvent() RetVal: true 
01-01 19:10:01.120: VERBOSE/MyView.onTouchEvent()(5930): Action: 2; PointerCount: 2; scaleGestureDetector.onTouchEvent() RetVal: true 
01-01 19:10:01.140: VERBOSE/MyView.onTouchEvent()(5930): Action: 2; PointerCount: 2; scaleGestureDetector.onTouchEvent() RetVal: true 
01-01 19:10:01.172: VERBOSE/MyView.onTouchEvent()(5930): Action: 2; PointerCount: 2; scaleGestureDetector.onTouchEvent() RetVal: true 
01-01 19:10:01.200: VERBOSE/MyView.onTouchEvent()(5930): Action: 2; PointerCount: 2; scaleGestureDetector.onTouchEvent() RetVal: true 
01-01 19:10:01.230: VERBOSE/MyView.onTouchEvent()(5930): Action: 2; PointerCount: 2; scaleGestureDetector.onTouchEvent() RetVal: true 
01-01 19:10:01.252: VERBOSE/MyView.onTouchEvent()(5930): Action: 2; PointerCount: 2; scaleGestureDetector.onTouchEvent() RetVal: true 
01-01 19:10:01.280: VERBOSE/MyView.onTouchEvent()(5930): Action: 2; PointerCount: 2; scaleGestureDetector.onTouchEvent() RetVal: true 
01-01 19:10:01.310: VERBOSE/MyView.onTouchEvent()(5930): Action: 2; PointerCount: 2; scaleGestureDetector.onTouchEvent() RetVal: true 
01-01 19:10:01.342: VERBOSE/MyView.onTouchEvent()(5930): Action: 2; PointerCount: 2; scaleGestureDetector.onTouchEvent() RetVal: true 
01-01 19:10:01.370: VERBOSE/MyView.onTouchEvent()(5930): Action: 2; PointerCount: 2; scaleGestureDetector.onTouchEvent() RetVal: true 
01-01 19:10:01.390: VERBOSE/MyView.onTouchEvent()(5930): Action: 2; PointerCount: 2; scaleGestureDetector.onTouchEvent() RetVal: true 
01-01 19:10:01.424: VERBOSE/MyView.onTouchEvent()(5930): Action: 2; PointerCount: 2; scaleGestureDetector.onTouchEvent() RetVal: true 
01-01 19:10:01.450: VERBOSE/MyView.onTouchEvent()(5930): Action: 2; PointerCount: 2; scaleGestureDetector.onTouchEvent() RetVal: true 
01-01 19:10:01.480: VERBOSE/MyView.onTouchEvent()(5930): Action: 2; PointerCount: 2; scaleGestureDetector.onTouchEvent() RetVal: true 
01-01 19:10:01.510: VERBOSE/MyView.onTouchEvent()(5930): Action: 2; PointerCount: 2; scaleGestureDetector.onTouchEvent() RetVal: true 
01-01 19:10:01.530: VERBOSE/MyView.onTouchEvent()(5930): Action: 2; PointerCount: 2; scaleGestureDetector.onTouchEvent() RetVal: true 
01-01 19:10:01.580: VERBOSE/MyView.onTouchEvent()(5930): Action: 2; PointerCount: 2; scaleGestureDetector.onTouchEvent() RetVal: true 
01-01 19:10:01.690: VERBOSE/MyView.onTouchEvent()(5930): Action: 2; PointerCount: 2; scaleGestureDetector.onTouchEvent() RetVal: true 
01-01 19:10:01.780: VERBOSE/MyView.onTouchEvent()(5930): Action: 2; PointerCount: 2; scaleGestureDetector.onTouchEvent() RetVal: true 
01-01 19:10:01.815: VERBOSE/MyView.onTouchEvent()(5930): Action: 2; PointerCount: 2; scaleGestureDetector.onTouchEvent() RetVal: true 
01-01 19:10:01.830: VERBOSE/MyView.onTouchEvent()(5930): Action: 262; PointerCount: 2; scaleGestureDetector.onTouchEvent() RetVal: true 
01-01 19:10:01.840: VERBOSE/MyView.onTouchEvent()(5930): Action: 1; PointerCount: 1; scaleGestureDetector.onTouchEvent() RetVal: true 

Como dije: ¡El valor de retorno siempre es "verdadero"! ¿Es esto un error de ScaleGestureDetector.onTouchEvent()? ¿Qué puedo hacer para que otros manejadores manejen todos los eventos que no sean de gesto de escala (por ejemplo, presionar prolongadamente con 1 dedo)? ¡Por favor ayuda!

Nemax

Respuesta

4

No sabe si se trata de un error o intencional, pero eso es sin duda lo que hace la fuente (ScaleGestureDetector.java:156):

public boolean onTouchEvent(MotionEvent event) { 
    final int action = event.getAction(); 
    boolean handled = true; 

    /* ... bunch of code that never updates 'handled' */ 

    return handled; 
} 

La forma en que esto fue resuelto para comprobar todos los otros tipos de eventos táctiles que deseo manejar primero, luego invocar el detector de gestos, por ej.

if (mLongPressGestureDetector != null && mLongPressGestureDetector.onTouchEvent(event)) 
     return true; 
    else if (mIsInMoveMode && mScaleGestureDetector != null) { 
     // Check for a move 
     if (action == MotionEvent.ACTION_MOVE && !mScaleGestureDetector.isInProgress()) { 
      handleMove(event); 
      return true; 
     } 

     // Now a scale 
     mScaleGestureDetector.onTouchEvent(event); 
     return true; 
    } 
+0

Hola Daren, gracias por su respuesta. El problema es que originalmente quería permitir que el controlador estándar de View "View.onTouchEvent()" manejara clics largos para poder usar la administración de menú de contexto estándar. Lo que automáticamente llama al método "onCreateContextMenu()" de la actividad, crea el diálogo del menú contextual, etc. Pero al llamar "super.onTouchEvent (event)" desde mi método "MyView.onTouchEvent()", siempre devuelve "true" también. ¿Ve alguna posibilidad de hacer a) que cooperen el controlador View.onTouchEvent() estándar y el manejador ScaleGestureDetector.onTouchEvent()? Saludos, Nemax – Nemax

+0

Sí, View.onTouchEvent siempre devuelve verdadero para las vistas clicables. ¿Has intentado siempre llamar a super.onTouchEvent()? Si eso no funciona, agregue su propio detector de gestos de pulsación larga como en el ejemplo que publiqué anteriormente, luego llame a performLongClick() cuando detecte un clic prolongado. –

2

El ScaleGestureDetector proporciona la isInProgress() método que podría hacer lo que quiera ...

Aquí es un ejemplo de ello en uso:

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; 
    } 

    return true; 
} 
+0

Hola alondra, de hecho, terminé usando el método "isInProgress()" del ScaleGestureDetector. Además de muchos otros trucos y métodos. Vea mi respuesta a mi propia pregunta anterior. – Nemax

2

Así es como he resuelto el problema: anulando el método onDispatchTouchEvent() de Acitivity. Cualquier otra solución parecía no funcionar. Lo bueno del método onDispatchTouchEvent() es que siempre se llama antes de reenviar cualquier evento táctil a cualquier otro receptor, por lo que puede interceptar cada evento táctil aquí.

Si el evento se maneja en alguna parte de aquí (escala o deslizamiento), regreso inmediatamente sin reenviar el evento a la superclase, i. mi. para el resto de la jerarquía de vista. Si no lo es, lo reenvío a la súper clase, para que otras vistas puedan manejarlo, e. gramo. para detectar clics cortos o largos.

Hubo algunos problemas más para resolver: 1. Si el usuario comienza un gesto de escala, tuve que cancelar cualquier proceso de detección de clic largo porque la vista de recepción obtendría el primer evento DOWN, luego nada más (después el segundo dedo baja y la escala comenzó), y luego, espuriamente, piensa que se está realizando una presión prolongada. 2. Cuando se realizó una pulsación larga y apareció el menú contextual, tuve que evitar la detección de gestos deslizantes y escala aquí en dispatchOnTouchEvent() hasta el próximo evento UP, de lo contrario se realizarían desplazamientos y escalas aunque el menú contextual esté allí.

Completamente complicado, pero pasé horas y horas y mucho ensayo y error, y simplemente no pude encontrar una solución más simple. De todos modos, el manejo de 1. gestos de escala, 2. gestos de deslizamiento horizontal, 3. gestos de desplazamiento vertical, 4. clics largos y 5. clics cortos, todos en la (s) misma (s) vista (s) objetivo (s), no es una misión muy sencilla de realizar. .

Aquí está el código (partes pertinentes de la misma):

@Override 
public boolean dispatchTouchEvent(MotionEvent e) { 
    if (eventInProgress) { 
     // View shall only receive scale gesture event if visible 
     if (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 event 
    switch (e.getAction()) { 
    case MotionEvent.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; 
    } 

    case MotionEvent.ACTION_MOVE: 
     // When having moved by too many x or y pixels, then 
     // cancel any ongoing long klick events 
     if (cancelLongPressEvent 
       && Math.abs(e.getX() - downXValue) 
         + Math.abs(e.getY() - downYValue) > 40) { 
      targetView.cancelLongPress(); 
      cancelLongPressEvent = false; 
     } 
     break; 

    case MotionEvent.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 right 
       if (deltaX > 0) { 
        flipRight(); 
        return (true); 
       } 
       // going forwards: pushing stuff to the left 
       if (deltaX < 0) { 
        flipLeft(); 
        return (true); 
       } 
       break; 
      } 
     } 
    } 
    } 

    // If event was not handled here, then forward it to parent, 
    // i. e. to view hierarchy 
    return (super.dispatchTouchEvent(e)); 
} 

[...]

@Override 
public void onCreateContextMenu(ContextMenu menu, View v, 
     ContextMenu.ContextMenuInfo menuInfo) { 
    super.onCreateContextMenu(menu, v, menuInfo); 
    MenuInflater mi = getMenuInflater(); 
    mi.inflate(R.menu.lztv_context_menu, menu); 
    contextMenuTargetView = v; 
    eventInProgress = false; 
} 
Cuestiones relacionadas