Mise en page Android: vue d’ensemble horizontale à l’intérieur d’une vue d’ensemble verticale à l’intérieur d’un Viewpager avec comportements de défilement

C’est l’application que j’essaie de construire avec tous les éléments présentés ci-dessous:

Application de légumes

Tout fonctionne, cependant, je veux que la recette horizontale interne ne capture aucun des défilement vertical. Tous les scrolls verticaux doivent aller vers la recyclerview verticale extérieure, et non horizontale, de sorte que le scroll vertical permette à la barre d’outils de sortir de la vue selon son scrollFlag.

Lorsque je mets le doigt sur la partie “StrawBerry Plant” de la vue de recyclage et que je fais défiler vers le haut, la barre d’outils défile:

plant de fraises

Si je place mon doigt sur la vue de défilement horizontale et que je fais défiler vers le haut, la barre d’outils ne défile pas du tout.

Voici mon code de présentation xml.

La disposition XML de l’ activité :

           

La disposition XML du fragment “Fruits” (qui est le code du fragment – le fragment est marqué dans l’image ci-dessus):

    <!--    

J’ai utilisé une classe personnalisée appelée VerticallyScrollRecyclerView, qui suit l’exemple Google de gestion des événements tactiles dans un groupe de vues. Son but est d’intercepter et de consumr tous les événements de défilement vertical pour qu’il défile dans / hors de la barre d’outils: http://developer.android.com/training/gestures/viewgroup.html

Le code de VerticallyScrollRecyclerView est ci-dessous:

 public class VerticallyScrollRecyclerView extends RecyclerView { public VerticallyScrollRecyclerView(Context context) { super(context); } public VerticallyScrollRecyclerView(Context context, AtsortingbuteSet attrs) { super(context, attrs); } public VerticallyScrollRecyclerView(Context context, AtsortingbuteSet 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 super.onInterceptTouchEvent(ev); // Do not intercept touch event, let the child handle it } switch (action) { case MotionEvent.ACTION_MOVE: { Log.e("VRecView", "its moving"); 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 (Math.abs(yDiff) > 5) { // Start scrolling! Log.e("Scroll", "we are scrolling vertically"); mIsScrolling = true; return true; } break; } } return super.onInterceptTouchEvent(ev); } private float calculateDistanceY(float endY) { return startY - endY; } } 

La mise en page “Favorite” qui est la recyclerview dans la recyclerview verticale:

       

Cela me dérange depuis un moment maintenant et je n’ai pas réussi à trouver une solution. Est-ce que quelqu’un sait comment résoudre ce problème?

5 points à Griffindor pour la bonne réponse et bien sûr, les points de réputation sur SO.

Solution testée:

Tout ce dont vous avez besoin est d’appeler mInnerRecycler.setNestedScrollingEnabled(false); sur votre intérieur RecyclerView s

Explication :

RecyclerView prend en charge le défilement nested introduit dans API 21 via l’implémentation de l’interface NestedScrollingChild . Ceci est une fonctionnalité précieuse lorsque vous avez une vue défilante dans une autre qui défile dans la même direction et que vous souhaitez faire défiler la View interne uniquement lorsqu’elle est focalisée.

Dans tous les cas, RecyclerView appelle par défaut RecyclerView.setNestedScrollingEnabled(true); sur lui-même lors de l’initialisation. Maintenant, revenons au problème, puisque vos deux RecyclerView trouvent dans le même ViewPager que AppBarBehavior , le CoordinateLayout doit décider à quel rouleau répondre lorsque vous faites défiler votre RecyclerView interne; Lorsque le défilement nested de votre interne RecyclerView est activé, il obtient le focus de défilement et CoordinateLayout choisira de répondre à son défilement sur le défilement externe de RecyclerView . La chose est que, puisque vos RecyclerView internes ne défilent pas verticalement, il n’y a pas de changement de défilement vertical (du sharepoint vue de CoordinateLayout ), et s’il n’y a pas de changement, AppBarLayout ne change pas non plus.

Dans votre cas, parce que vos objects RecyclerView internes défilent dans une direction différente, vous pouvez la désactiver, ce qui fait que CoordinateLayout ignore son défilement et répond au défilement externe de RecyclerView .

Avis :

L’atsortingbut xml android:nestedScrollingEnabled="boolean" n’est pas destiné à être utilisé avec RecyclerView , et une tentative d’utilisation d’ android:nestedScrollingEnabled="false" entraînera une java.lang.NullPointerException , du moins pour le moment, vous aurez le faire en code.

Solution testée, utilisez un NestedScrollView() personnalisé NestedScrollView() .

Code:

 public class CustomNestedScrollView extends NestedScrollView { public CustomNestedScrollView(Context context, AtsortingbuteSet attrs) { super(context, attrs); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { if (ev.getAction() == MotionEvent.ACTION_DOWN) { // Explicitly call computeScroll() to make the Scroller compute itself computeScroll(); } return super.onInterceptTouchEvent(ev); } } 

Je suis un peu en retard mais cela fonctionnera bien pour les autres personnes confrontées au même problème

  mRecyclerView.addOnItemTouchListener(new RecyclerView.OnItemTouchListener() { @Override public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) { int action = e.getAction(); // Toast.makeText(getActivity(),"HERE",Toast.LENGTH_SHORT).show(); switch (action) { case MotionEvent.ACTION_POINTER_UP: rv.getParent().requestDisallowInterceptTouchEvent(true); break; } return false; }