2010-11-11 12 views
16

Estoy tratando de detectar un evento fling en una aplicación simple de Android, pero el primer argumento MotionEvent es siempre nulo. ¿Por qué se llama al método onFling con un argumento nulo? El Android documentation dice que se llama cuando se produce un evento fling con el MotionEvent inicial y posterior y el evento MotionEvent correspondiente.Android SimpleOnGestureListener.onFling obteniendo un evento nulo MotionEvent

class MyGestureDetector extends SimpleOnGestureListener { 
    @Override 
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { 
     // e1 always == null, return early a null reference exception 
     if (e1 == null) { 
      return false; 
     } 
     if (e1.getY() - e2.getY() > 120) { 
      handleFlingEvent(); 
      return true; 
     } 
     return false; 
    } 
} 

La actividad principal de este método tiene onTouchEvent:

GestureDetector flingDetector = new GestureDetector(new MyGestureDetector()); 

@Override 
public boolean onTouchEvent(MotionEvent event) { 
    if (flingDetector.onTouchEvent(event)) { 
     return true; 
    } 
    return super.onTouchEvent(event); 
} 

Respuesta

2

Tengo el mismo problema. Sucede cuando GestureDetector y el método onFling estaban en una clase de vista personalizada, que forma parte de la IU de actividad. Después de una serie de pruebas, descubrí que solo la actividad principal puede detectar bien el gesto de deslizar. Entonces resuelvo el problema reemplazándolo en la actividad. Pero no encontré la causa raíz de este problema.

+0

Lo conseguí para trabajar, pero nunca pude determinar qué finalmente lo hizo.Su solución se aplica en mi caso, así que acepté su respuesta. Me gustaría saber por qué no funcionó. – mcrumley

+0

Yo también. Me gustaría saber por qué no funcionó tan bien. Espero que alguien responda eso. –

+0

¿Has tenido algo de suerte rastreando la causa de esto? Estoy sufriendo el mismo problema pero parece que no funciona, incluso con el método onFling en la actividad principal. –

2

Tenía 3 botones en el diseño lineal horizontal y este diseño a su vez rodeado por horizontalscrollview.

Luego configuré simplegesturelistener en el horizontalscrollview y obtuve el mismo error que el anterior. Luego también configuré simplegesturelistener para todos los botones en el diseño y funcionó.

12

Primero encontré este problema con Android 4.0 ya que mi código funciona bien en todas las versiones anteriores. Después de seguir el ejemplo de las sugerencias aquí, he encontrado que una solución fácil es hacer un seguimiento del evento onDown y usarlo en lugar del primer parámetro de onFling en caso de que sea nulo.

public class MySimpleGestureListener extends SimpleOnGestureListener { 
    protected MotionEvent mLastOnDownEvent = null; 

    @Override 
    public boolean onDown(MotionEvent e) { 
     mLastOnDownEvent = e; 
     return true;//super.onDown(e); 
    } 

    @Override 
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { 
     if (e1==null) 
      e1 = mLastOnDownEvent; 
     if (e1==null || e2==null) 
      return false; 
     float dX = e2.getX()-e1.getX(); 
     float dY = e2.getY()-e1.getY(); 
     ...rest of code 
    } 

    ...rest of class 
} 
+0

Intenté esto, pero no me solucionó el problema. onDown no se llama y e1 sigue siendo nulo. – fobbymaster

+0

@fobbymaster en callback 'onDown' solo devuelve' true' en lugar de 'super.onDown (e)' – 0neel

0

Creo que el evento onDown se ha reanudado por el ScrollView, por lo que no se puede obtener el evento en la actividad. Si personalizó un ScrollView e invalida el dispatchTouchEvent() y onTouchEvent(), el problema se resolverá.

Actividad:

public class TestActivity extends Activity { 
    private MyScrollView scrollView; 
    private TestActivity me; 
    private GestureDetector detector; 

    protected void onCreate(Bundle savedInstanceState) { 
      this.me = this; 
      MySimpleGestureListener gestureListener = new MySimpleGestureListener(); 
      this.detector = new GestureDetector(gestureListener); 
      this.scrollView.setOnTouchListener(onTouchListerner); 
      this.scrollView.setDetector(detector); 
    } 

    private View.OnTouchListener onTouchListener = new View.OnTouchListener() { 
    @Override 
    public boolean onTouch(View v, MotionEvent event) { 
     return me.detector.onTouchEvent(event); 
    } 
}; 
} 

MySimpleGestureListener:

public class MySimpleGestureListener extends SimpleOnGestureListener { 
    @Override 
    public boolean onSingleTapUp(MotionEvent e) { 
     return false; 
    } 

    @Override 
    public void onShowPress(MotionEvent e) { 

    } 

    @Override 
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, 
      float distanceY) { 
     return super.onScroll(e1, e2, distanceX, distanceY); 
    } 

    @Override 
    public void onLongPress(MotionEvent e) { 
    } 


    @Override 
    public boolean onDown(MotionEvent e) { 
     return false; 
    } 

    @Override 
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, 
      float velocityY) { 
        // TODO do your onFling here 

    } 
} 

Por fin, MyScrollView

public class MyScrollView extends ScrollView { 
    private GestureDetector detector; 

    @Override 
public boolean dispatchTouchEvent(MotionEvent ev){ 
    if (this.detector!= null) { 
      detector.onTouchEvent(ev); 
     super.dispatchTouchEvent(ev); 
     return true; 
    } 
    return super.dispatchTouchEvent(ev); 
} 

@Override 
public boolean onTouchEvent(MotionEvent ev) { 
    super.onTouchEvent(ev); 
    // 
    if (this.detector != null) { 
     return this.detector.onTouchEvent(ev); 
    } 
    return false; 
} 

    // here is the getter and setter 
} 

Esperanza esta ayuda.

3

En la clase de grupo de vista personalizada debe reemplazar 2 métodos: onInterceptTouchEvent y onTouchEvent. Después de eso, debe llamar al GestureDetector.onTouchEvent() en ambos métodos. El evento ACTION_DOWN se pasa al onInterceptTouchEvent solamente.

@Override 
public boolean onInterceptTouchEvent(MotionEvent event) { 
    if(mDetector.onTouchEvent(event)) { 
     return true; 
    } 
    return super.onInterceptTouchEvent(event); 
} 

@Override 
public boolean onTouchEvent(MotionEvent event) { 
    if(mDetector.onTouchEvent(event)) { 
     return true; 
    } 
    return super.onTouchEvent(event); 
} 
Cuestiones relacionadas