GestureDetector fling dirección equivocada

Tengo una implementación de un BottomDrawer que implementa GestureDetector para determinar cuando el usuario lanza el cajón inferior. Tengo dos problemas con esto:

1) El onFling no siempre se llama. Este es un problema relativamente menor.

2) La velocidad que se pasa al onFling es con frecuencia de la dirección equivocada. Este es un gran problema, ya que conduce al usuario que lanza el cajón para cerrar, y la apertura, o viceversa. ¿Es este un tema que alguien ha encontrado antes? ¿Como puede ésto ser resuelto? Pensé que tal vez ignorar los lanzamientos de menos de una cierta magnitud, pero las velocidades erróneas a veces puede ser de una magnitud bastante grande, por lo que no ayuda.

Aquí está el código de mi clase BottomDrawer , también puedo subir un proyecto de demostración a GitHub si eso sería útil:

 package com.cbendeb.bottomdrawer.view; import android.animation.Animator.AnimatorListener; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.GestureDetector; import android.view.MotionEvent; import android.widget.LinearLayout; /** * A bottom extensible drawer. Displays two views, one as the handle and one as the content. * * @author catherine */ public final class BottomDrawer extends LinearLayout implements GestureDetector.OnGestureListener { private static final String TAG = BottomDrawer.class.getSimpleName(); private static final int ANIMATE_DURATION = 500; private float lastTouchY; // so we don't have to recalculate this stuff all the time private float openY; private float closedY; private float currentY = -1; // listeners for the end of the open and close animations private AnimatorListener closeListener; private AnimatorListener openListener; // gestures private GestureDetector gestureDetector; private boolean flung = false; public BottomDrawer(Context context) { super(context); init(context); } public BottomDrawer(Context context, AttributeSet attrs) { super(context, attrs); init(context); } public BottomDrawer(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(context); } private void init(Context context) { setOrientation(LinearLayout.VERTICAL); gestureDetector = new GestureDetector(context, this); } /** * @return true if the drawer is expanded */ public boolean isOpen() { return currentY != closedY; } /** * Opens the drawer. */ public void open() { animate() .translationY(0) .setDuration( Math.max(0, (int) (ANIMATE_DURATION * (getY() - openY) / (closedY - openY)))) .setListener(openListener).start(); } /** * Closes the drawer. */ public void close() { animate() .translationY(getChildAt(1).getHeight()) .setDuration( Math.max(0, (int) (ANIMATE_DURATION * (closedY - getY()) / (closedY - openY)))) .setListener(closeListener).start(); } @Override public boolean onTouchEvent(MotionEvent ev) { final int action = ev.getActionMasked(); final float y = ev.getRawY(); gestureDetector.onTouchEvent(ev); switch (action) { case MotionEvent.ACTION_DOWN: break; case MotionEvent.ACTION_MOVE: // Calculate the distance moved final float dy = y - lastTouchY; if (getY() + dy < closedY && getY() + dy > openY) { setY(getY() + dy); invalidate(); } break; case MotionEvent.ACTION_CANCEL: flung = false; break; case MotionEvent.ACTION_UP: Log.d(TAG, "flung: " + flung); if (!flung) { if (getY() >= (openY + closedY) / 2) { Log.d(TAG, "closing"); close(); } else { Log.d(TAG, "opening"); open(); } } flung = false; break; case MotionEvent.ACTION_POINTER_UP: break; } lastTouchY = y; return true; } @Override public void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); openY = getBottom() - getChildAt(0).getHeight() - getChildAt(1).getHeight(); closedY = getBottom() - getChildAt(0).getHeight(); if (currentY == -1) { currentY = closedY; } if (changed && isOpen()) { setY(openY); } else if (changed && !isOpen()) { setY(closedY); } } @Override public boolean onDown(MotionEvent e) { return true; } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { Log.d(TAG, "onFling velocityY: " + velocityY + " currentY " + currentY); final float y = getY(); if (velocityY < 0 && y > openY && y < closedY) { // moving upwards Log.d(TAG, "onFling opening"); open(); } else if (velocityY > 0 && y > openY && y < closedY) { // moving downwards Log.d(TAG, "onFling closing"); close(); } flung = true; return true; } @Override public void onLongPress(MotionEvent e) { // Do nothing } @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { return false; } @Override public void onShowPress(MotionEvent e) { // Do nothing } @Override public boolean onSingleTapUp(MotionEvent e) { // Do nothing return false; } } 

Estoy buscando en la implementación GestureDetector en GrepCode … pero sería bueno si había una manera más fácil de resolver esto.

FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.