2010-12-15 55 views
2

J'ai une application simple avec deux vues, l'une est une TableView et l'autre est ListView. J'utilise GestureDetector pour détecter les balayages à travers l'écran de la même façon que c'est fait here. Tout fonctionne bien, si l'affichage de la liste est rempli avec quelques éléments, mais lorsque la ListView remplit tout l'écran, la détection des mouvements cesse de fonctionner. Faire le balayage sur l'écran montre simplement met en évidence l'un des éléments de la liste.Le détecteur de mouvement ne fonctionne pas avec l'activité de liste déroulante

Je pense que cela se produit parce que ListView vole en quelque sorte les événements tactiles de GestureListener. Est-ce qu'il y a un moyen d'éviter cela?

Répondre

1

Vous pouvez créer une vue de liste personnalisée, puis implémenter le détecteur de mouvement à l'intérieur de ce champ, c'est-à-dire sur chaque ligne de la liste. Ça pourrait valoir la peine d'essayer.

+0

Je pensais à ce sujet, mais la recherche de quelque chose plus propre. – Vlad

2

J'ai trouvé que GestureDetector fonctionne correctement dans ListItems si vous parcourez un chemin horizontal assez précis. Cependant si vous vous écartez légèrement, la liste défile et le geste ne se termine pas. Ce qui se passe est la suivante:

  • Le GestureDetector commence en prenant joyeusement MotionEvents de la OnTouch que vous installez dans les ListItems via setOnTouchListener(). Le ListView est en train d'écouter les événements envoyés à ses vues enfants via onInterceptTouchEvent()
  • ListView détecte que vous avez commencé à faire défiler et renvoie true à partir de onInterceptTouchEvent(). A partir de ce moment-là, les événements MotionEvents sont envoyés à ListView et PAS à la cible d'origine ... ListView commence à recevoir MotionEvents dans son gestionnaire onTouch. Cela continue jusqu'à la dernière ACTION_UP. (Notez que les MotionEvents de ACTION_DOWN à travers tous les ACTION_MOVEs à ACTION_UP sont considérés comme un seul geste et tout recommence après l'ACTION_UP final de la séquence)
  • La cible d'origine (ListItem) reçoit un ACTION_CANCEL MotionEvent et le GestureDetector dans vos listes ListItem en dehors. Cela peut être vu se produire si vous collez le code pour GestureDetector dans votre application et passez à travers elle.

J'avais besoin que mon application se comporte comme si le balayage horizontal continuait même si le toucher s'éloignait légèrement de l'horizontale.

SOLUTION: Cela implique ViewGroup.requestDisallowInterceptTouchEvent (boolean disallowIntercept) qui empêche le parent de visualiser les événements de mouvement. La méthode consiste à implémenter onTouchListener pour détecter un léger balayage (10 pixels environ), puis arrêter le parent d'intercepter les événements de mouvement. Le parent ne défilera alors pas et le détecteur de mouvement continuera jusqu'à la fin.

Voici le code:

private boolean mFlingInProgress = false; 
private float mStartX = 0; 
private final int FLING_TRIGGER_DISTANCE = 10; 

@Override 
public boolean onTouch(View v, MotionEvent event) { 
    int action = event.getAction(); 
    float currentX = event.getRawX(); 

    switch (action) { 
    case MotionEvent.ACTION_DOWN: 
     mStartX = currentX; 
     break; 
    case MotionEvent.ACTION_MOVE: 
     if (false == mFlingInProgress) { 
      if (Math.abs(currentX - mStartX) > FLING_TRIGGER_DISTANCE) { 
       // stop the parent intercepting motion events 
       mLayout.getParent().requestDisallowInterceptTouchEvent(true); 
       mFlingInProgress = true; 
      } 
     } 
     break; 
    case MotionEvent.ACTION_UP: 
     mFlingInProgress = false; 
     break; 
    } 

    return mGestureDetector.onTouchEvent(event); 
}