tube - Android SimpleOnGestureListener.onFling obtiene un MotionEvent nulo
touch events android (6)
Estoy intentando detectar un evento de lanzamiento en una aplicación de Android simple, pero el primer argumento de MotionEvent
siempre es nulo. ¿Por qué se llama al método onFling con un argumento nulo? La documentación de Android dice que se llama cuando ocurre un evento de lanzamiento con la inicial abajo en MotionEvent y la coincidencia con 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 tiene este método onTouchEvent:
GestureDetector flingDetector = new GestureDetector(new MyGestureDetector());
@Override
public boolean onTouchEvent(MotionEvent event) {
if (flingDetector.onTouchEvent(event)) {
return true;
}
return super.onTouchEvent(event);
}
Creo que el evento onDown ha sido reanudado por la vista de desplazamiento, por lo que no podemos obtener el evento en la actividad. Si personaliza un ScrollView y anula 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
}
Espero que esto ayude.
En la clase de grupo de vista personalizada, necesita anular 2 métodos: onInterceptTouchEvent
y onTouchEvent
. Después de eso, debe llamar a GestureDetector.onTouchEvent()
en ambos métodos. El evento ACTION_DOWN
se pasa solo a onInterceptTouchEvent
.
@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);
}
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, he encontrado que una solución alternativa es simplemente 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
}
Tenía 3 botones en diseño lineal horizontal y este diseño, a su vez, estaba rodeado de vista horizontalscrollview
.
Luego puse simplegesturelistener
en la vista simplegesturelistener
horizontalscrollview
y obtuve el mismo error que el anterior. Luego también simplegesturelistener
para todos los botones en el diseño y funcionó.
Tengo el mismo problema con la vista personalizada y OnGestureListener onFling. Descubrí esto:
Ya sea que use o no GestureDetector.SimpleOnGestureListener, siempre debe implementar un método onDown () que devuelva true.
Obtenido de http://developer.android.com/training/custom-views/making-interactive.html
Tengo el problema similar. Ocurre cuando el GestureDetector y el método onFling estaban en una clase de vista personalizada, que forma parte de la IU de la 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ándolos en la actividad. Pero no encontré la causa raíz de este problema.