4

Cela semble être un modèle assez commun dans Android. Je suis en train de créer quelque chose de similaire à la façon dont Facebook affiche leurs annonces:Android: Recyclerview horizontal à l'intérieur d'un Recyclerview vertical

Facebook ads

Vous pouvez voir qu'ils ont une recyclerview verticale extérieure avec une recyclerview horizontale intérieure comme l'un des éléments dans l'adaptateur de la recyclerview verticale extérieure .

J'ai suivi ce guide de Google sur "Gestion des événements tactiles dans un ViewGroup" - http://developer.android.com/training/gestures/viewgroup.html comme Recyclerview étend ViewGroup et le code est similaire à ce que je veux faire.

Je l'ai personnalisé un peu de sorte qu'il détecte les mouvements dans l'axe Y au lieu des mouvements dans l'axe X et l'a appliqué à la vue de recyclage verticale extérieure.

/** 
* Created by Simon on 10/11/2015. 
*///This is the recyclerview that would allow all vertical scrolls 
public class VerticallyScrollRecyclerView extends RecyclerView { 


    public VerticallyScrollRecyclerView(Context context) { 
     super(context); 
    } 

    public VerticallyScrollRecyclerView(Context context, AttributeSet attrs) { 
     super(context, attrs); 
    } 

    public VerticallyScrollRecyclerView(Context context, AttributeSet attrs, int defStyle) { 
     super(context, attrs, defStyle); 
    } 


    ViewConfiguration vc = ViewConfiguration.get(this.getContext()); 
    private int mTouchSlop = vc.getScaledTouchSlop(); 
    private boolean mIsScrolling; 
    private float startY; 

    @Override 
    public boolean onInterceptTouchEvent(MotionEvent ev) { 
     final int action = MotionEventCompat.getActionMasked(ev); 
     // Always handle the case of the touch gesture being complete. 
     if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) { 
      // Release the scroll. 
      mIsScrolling = false; 
      startY = ev.getY(); 
      return false; // Do not intercept touch event, let the child handle it 
     } 
     switch (action) { 
      case MotionEvent.ACTION_MOVE: { 
       if (mIsScrolling) { 
        // We're currently scrolling, so yes, intercept the 
        // touch event! 
        return true; 
       } 

       // If the user has dragged her finger horizontally more than 
       // the touch slop, start the scroll 

       // left as an exercise for the reader 
       final float yDiff = calculateDistanceY(ev.getY()); 
       Log.e("yDiff ", ""+yDiff); 
       // Touch slop should be calculated using ViewConfiguration 
       // constants. 
       if (yDiff > mTouchSlop) { 
        // Start scrolling! 
        Log.e("Scroll", "we are scrolling vertically"); 
        mIsScrolling = true; 
        return true; 
       } 
       break; 
      } 
     } 
     return false; 
    } 

    private float calculateDistanceY(float endY) { 
     return startY - endY; 
    } 

} 

Ma mise en page xml:

<?xml version="1.0" encoding="utf-8"?> 
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:orientation="vertical" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:id="@+id/main_recyclerview_holder"> 

    <com.example.simon.customshapes.VerticallyScrollRecyclerView 
     android:id="@+id/main_recyclerview" 
     android:layout_width="match_parent" 
     android:layout_height="match_parent" 
/> 

</RelativeLayout> 

Lorsque je tente de faire glisser le recyclerview intérieur horizontal (en espérant que la TouchEvent serait interceptée par la recyclerview verticale extérieure), la recyclerview extérieure ne défile pas verticalement à tout.

Il me donne aussi une erreur en disant:

Erreur dans le traitement défilement; index de pointeur pour id -1 non trouvé. Est-ce que MotionEvents a été sauté?

Est-ce que quelqu'un sait comment fonctionner correctement?

+1

Pourquoi avez-vous besoin de créer votre 'VerticallyScrollRecyclerView' personnalisé? Vous ne pouvez pas utiliser un 'LinearLayoutManager' horizontal? – rciovati

+0

J'utilise un LinearLayoutManager horizontal dans le recyclerview horizontal. Le recyclerview externe utilise un LinearLayoutManager vertical. Cette question est basée sur le code correct pour implémenter des touches et j'ai besoin de la fonction VerticallyScrollRecyclerView parce que j'en ai besoin pour intercepter tous les déplacements afin qu'ils défilent correctement. Sinon, il y aura des conflits de toucher entre la vue interne et externe du recycleur. – Simon

+0

Avez-vous trouvé une solution? – Shubham

Répondre

0

J'ai rencontré un problème similaire et je n'ai trouvé aucune solution en ligne. Dans mon application, j'ai une liste d'éléments interactifs personnalisés, avec lesquels vous pouvez interagir glisser horizontalement (et dans ce cas, le défilement devrait être verrouillé), mais lorsque vous balayez verticalement, il devrait défiler. Selon vos commentaires vous avez déjà résolu votre problème, mais pour ceux, dont le problème est similaire au mien et dont la recherche les a conduits ici, je posterai ma solution. J'ai regardé un peu sous le capot de RecyclerView, et voici ce que j'ai trouvé. "Erreur lors du traitement du défilement: l'index du pointeur pour l'ID -1 est introuvable. Des événements MotionEvents ont-ils été ignorés?" - le problème est que la variable mScrollPointerId, qui est utilisée pour obtenir index, est définie dans onTouchEvent quand ACTION_DOWN arrive.Dans mon cas particulier quand ACTION_DOWN arrive, je retourne false de onInterceptTouchEvent, puisque à ce moment je ne sais pas l'utilisateur météo veut faites défiler ou interagissez avec l'élément de liste. Et dans ce cas, onTouchEvent n'est pas appelée. Plus tard, quand je découvre que l'utilisateur veut interchanger avec l'élément, je rentre faux de onInterceptTouchEvent et onTouchEvent est appelé, mais il ne peut pas traiter le défilement parce que mScrollPointerId n'est pas défini. La solution ici est juste d'appeler onTouchEvent de onInterceptTouchEvent lorsque ACTION_DOWN se produit.

@Override 
public boolean onInterceptTouchEvent(MotionEvent e) { 
    ... 
    switch (action) { 
     case MotionEvent.ACTION_DOWN: { 
      onTouchEvent(e); 
      ... 
      break; 
      } 
     ... 
     } 
    ... 
}