2011-01-13 16 views
10

Tengo una actividad que contiene un ViewFlipper. El ViewFlipper incluye 2 diseños, los cuales son esencialmente solo ListViews.Problemas para detectar gestos en ListView

Así que la idea aquí es que tengo dos listas y para navegar de una a otra usaría un deslizamiento horizontal.

Tengo que funcionar. Sin embargo, cualquiera que sea el elemento de la lista en el que se encuentre el dedo cuando el deslizamiento comience a ejecutarse, también se hará clic largo en ese elemento.

Este es el código correspondiente que tengo:

public class MyActivity extends Activity implements OnItemClickListener, OnClickListener { 

    private static final int SWIPE_MIN_DISTANCE = 120; 
    private static final int SWIPE_MAX_OFF_PATH = 250; 
    private static final int SWIPE_THRESHOLD_VELOCITY = 200; 

    private GestureDetector mGestureDetector; 
    View.OnTouchListener mGestureListener; 

    class MyGestureDetector extends SimpleOnGestureListener { 
     @Override 
     public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { 
      try { 
       if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH) 
        return false; 
       // right to left swipe 
       if(e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) { 
        if (mCurrentScreen != SCREEN_SECONDLIST) { 
         mCurrentScreen = SCREEN_SECONDLIST; 
         mFlipper.setInAnimation(inFromRightAnimation()); 
         mFlipper.setOutAnimation(outToLeftAnimation()); 
         mFlipper.showNext(); 
         updateNavigationBar(); 
        } 
       } 
       else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) { 
        if (mCurrentScreen != SCREEN_FIRSTLIST) { 
         mCurrentScreen = SCREEN_FIRSTLIST; 
         mFlipper.setInAnimation(inFromLeftAnimation()); 
         mFlipper.setOutAnimation(outToRightAnimation()); 
         mFlipper.showPrevious(); 
         updateNavigationBar(); 
        } 
       } 
      } catch (Exception e) { 
       // nothing 
      } 
      return true; 
     } 
    } 

    @Override 
    public boolean onTouchEvent(MotionEvent event) { 
     if (mGestureDetector.onTouchEvent(event)) 
      return true; 
     else 
      return false; 
    } 





    ViewFlipper mFlipper; 

    private int mCurrentScreen = SCREEN_FIRSTLIST; 

    private ListView mList1; 
    private ListView mList2; 

    /** Called when the activity is first created. */ 
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

     requestWindowFeature(Window.FEATURE_NO_TITLE); 
     setContentView(R.layout.layout_flipper); 

     mFlipper = (ViewFlipper) findViewById(R.id.flipper); 

     mGestureDetector = new GestureDetector(new MyGestureDetector()); 
     mGestureListener = new View.OnTouchListener() { 
      public boolean onTouch(View v, MotionEvent event) { 
       if (mGestureDetector.onTouchEvent(event)) { 
        return true; 
       } 
       return false; 
      } 
     }; 

     // set up List1 screen 

     mList1List = (ListView)findViewById(R.id.list1); 
     mList1List.setOnItemClickListener(this); 
     mList1List.setOnTouchListener(mGestureListener); 

     // set up List2 screen 
     mList2List = (ListView)findViewById(R.id.list2); 
     mList2List.setOnItemClickListener(this); 
     mList2List.setOnTouchListener(mGestureListener); 

    } 

    … 
} 

Si cambio la "return true;" declaración del GestureDetector para "devolver falso;", no obtengo clics largos. Lamentablemente, obtengo clics regulares.

¿Alguien sabe cómo puedo evitar esto?

Respuesta

7

solo para arrojarlo en una respuesta completamente diferente con un enfoque completamente diferente ...

He hecho una vista personalizada llamada SwipeView, es de código abierto, etc, etc, bla, bla, bla. Se le debe permitir hacer lo que quiere hacer tan simple como ir:

mSwipeView.addChild(myList1); 
mSwipeView.addChild(myList2); 

Usted no tendrá que enredar con detectores gesto o nada, y la del golpe debe seguir el dedo como lo haces ..

(Esto parece un terrible y terrible anuncio, discúlpeme.Ha sido un día largo;)

tienen algunos enlaces maravillosos:

http://jasonfry.co.uk/?id=23

http://jasonfry.co.uk/?id=24

http://jasonfry.co.uk/?id=28

+0

Esto es similar a un componente que desarrollé recientemente, excepto que agregué el reciclaje de vistas a la mina y su respaldado por un listAdapter. Básicamente, aprendí un montón de código ListView y lo adjunté a un gesto personalizado impulsado HorizontalScrollView como lo hiciste. – jfelectron

+0

¡Sí, estoy trabajando para agregar eso a SwipeView también! Además, me acabo de enterar (literalmente, hace unos 2 minutos) de que hay un error con ListViews en SwipeView. Ya arreglé el error y actualicé el git repo. https://github.com/fry15/uk.co.jasonfry.android.tools – jsonfry

+3

jfelectron es tuyo en GIThub sin embargo? –

0

[EDITAR] Raspe eso, totalmente equivocado.

Creo que debería actualizar esta parte, y detectar si estaba desplazándose hacia la izquierda o hacia la derecha, y devolver verdadero si estaba en un estado de deslizamiento. O al menos ahí es donde miraría primero.

mGestureListener = new View.OnTouchListener() { 
      public boolean onTouch(View v, MotionEvent event) { 
       if (mGestureDetector.onTouchEvent(event)) { 
        return true; 
       } 
       return false; 
      } 
     }; 

Continuando con mi pobre ejemplo, lo siento.

Dentro del onTouch creo que puede probar event.getAction() y determinar si se ha producido un clic prolongado. Si lo ha hecho, y usted en un movimiento arrojadizo, entonces regrese verdadero como para capturar el clic largo.

Miedo esto es más una sugerencia que una respuesta definitiva.

También haga que compruebe el otro en [métodos] que puede anular desde SimpleOnGestureListener. Acabo de marcar y

@Override 
public void onLongPress(MotionEvent e) { 
    // TODO Auto-generated method stub 
    super.onLongPress(e); 
} 

podría ser algo con lo que podría experimentar.

+0

Eso es lo que está sucediendo. ¿O es su ejemplo lo que su EDITACIÓN intenta invalidar? – Andrew

+0

Lo siento, es un terrible ejemplo, ha estado solucionando otro problema. Intentaremos y explicaremos mejor más tarde. – Emile

1

Dado que está utilizando un GestureDetector, lo que hay que hacer es implementar SimpleGestureDetector.onLongPress(MotionEvent e) para manejar clics largos. Sin embargo, no puede conocer el elemento de lista que se ha presionado desde allí, por lo que debe recordarlo desde el onItemLongClick() normal.

class MyGestureDetector extends SimpleOnGestureListener { 
    ... 
    @Override public void onLongPress(MotionEvent e) { 
     if (longClickedItem != -1) { 
      Toast.makeText(MainActivity.this, "Long click!", Toast.LENGTH_LONG).show(); 
     }   
    } 
} 

int longClickedItem = -1; 

@Override 
public boolean onItemLongClick(AdapterView<?> list, View view, int position, long id) { 
    longClickedItem = position; 
    return true; 
} 

@Override 
public boolean onTouchEvent(MotionEvent event) { 

    // Reset longclick item if new touch is starting 
    if (event.getAction()==MotionEvent.ACTION_DOWN) { 
     longClickedItem = -1; 
    } 

    if (mGestureDetector.onTouchEvent(event)) 
     return true; 
    else 
     return false; 
} 

He probado esto y parece funcionar bien.

+0

Gracias por su respuesta. Voy a darle una oportunidad. Debo señalar que, si bien una pulsación larga es lo que se está activando y es lo que he notado, lo que realmente me gustaría que ocurra es no tener una fuga de gestos si alguien está deslizando. Hay algunos otros problemas, especialmente con teléfonos Android que pueden hacer las animaciones de fin de lista de iPhone, etc. El verdadero problema aquí es que deslizar es enviar otros gestos a la lista; y no sé cómo detener eso. – Andrew

+0

Acabo de probar esto y evita que se ejecute el clic prolongado cuando deslizo, aunque el elemento en el que se origina el dedo resalta el amarillo; entonces alguna parte del gesto obviamente se está escapando a la lista – Andrew

+0

Intente llamar a list.cancelLongPress() si el detector de gestos devuelve verdadero ... –

1

que sigue tu gestureDetector y establecer

mGestureDetector.setIsLongpressEnabled(false); 

Esto evitará que se detecten eventos de pulsación larga.

0

Desarrollé un componente personalizado derivado de horizontalScrollView que hace esto. Tengo listViews mientras el niño ve y desliza sin presionar de manera prolongada. Está respaldado por un listAdapter, que podría ser cualquier cosa que desee (ArrayAdapter, CursorAdapter ...). Carga hasta tres vistas secundarias y luego al voltearlas, simplemente las intercambia en ambos lados. La mayor parte de esto se elimina de ListView y necesita ser refactorizado. Es demasiado tiempo para publicar aquí directamente.

http://pastie.org/1480091

0

Retire su getListView().setOnItemLongClickListener

Añadir en su clase MyGestureDetector:

public void onLongPress(MotionEvent e) { 
    final int position = getListView().pointToPosition((int) e.getX(), 
      (int) e.getY()); 
    // what you want do 
    super.onLongPress(e); 
} 
Cuestiones relacionadas