web-dev-qa-db-fra.com

NestedScrolling avec NestedScrollView, RecyclerView (Horizontal), dans un CoordinatorLayout

J'ai une conception d'interface utilisateur avec CollapsingToolbarLayout, comme suit.

<Android.support.design.widget.AppBarLayout
    Android:id="@+id/appbar"
    Android:layout_width="match_parent"
    Android:layout_height="@dimen/detail_backdrop_height"
    Android:fitsSystemWindows="true"
    Android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

    <Android.support.design.widget.CollapsingToolbarLayout

        Android:id="@+id/collapsing_toolbar"
        Android:layout_width="match_parent"
        Android:layout_height="match_parent"
        Android:fitsSystemWindows="true"
        app:contentScrim="?attr/colorPrimary"
        app:expandedTitleMarginEnd="64dp"
        app:expandedTitleMarginStart="48dp"
        app:layout_scrollFlags="scroll|exitUntilCollapsed">

        <ImageView
            Android:id="@+id/backdrop"
            Android:layout_width="match_parent"
            Android:layout_height="match_parent"
            Android:fitsSystemWindows="true"
            Android:scaleType="centerCrop"
            app:layout_collapseMode="parallax" />

        <Android.support.v7.widget.Toolbar
            Android:id="@+id/toolbar"
            Android:layout_width="match_parent"
            Android:layout_height="?attr/actionBarSize"
            app:layout_collapseMode="pin"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />

    </Android.support.design.widget.CollapsingToolbarLayout>

</Android.support.design.widget.AppBarLayout>

<Android.support.v4.widget.NestedScrollView
    Android:layout_width="match_parent"
    Android:layout_height="wrap_content"
    Android:fillViewport="true"
    Android:theme="@style/ThemeOverlay.AppCompat.Light"
    app:layout_behavior="@string/appbar_scrolling_view_behavior">

    <LinearLayout
        Android:layout_width="match_parent"
        Android:layout_height="wrap_content"
        Android:orientation="vertical"
        Android:paddingTop="24dp">

        <!-- Hiding unrelated code -->

        <Android.support.v7.widget.CardView
            Android:layout_width="match_parent"
            Android:layout_height="wrap_content"
            Android:layout_margin="@dimen/card_margin"
            Android:padding="16dp">


                <Android.support.v7.widget.RecyclerView
                    Android:id="@+id/recycler_movie_suggestion"
                    Android:layout_width="match_parent"
                    Android:layout_height="170dp"
                    Android:fillViewport="true"
                    Android:nestedScrollingEnabled="false"
                    app:layout_behavior="@string/appbar_scrolling_view_behavior" />

            </LinearLayout>

        </Android.support.v7.widget.CardView>

    </LinearLayout>

</Android.support.v4.widget.NestedScrollView>

Mon problème est que le défilement est correct UNIQUEMENT lorsque je touche et fait défiler la zone EN DEHORS du RecyclerView. Si j'essaie de faire défiler verticalement à l'intérieur de RecyclerView, le défilement est "piégé" et SEUL le NestedScrollView défile, la CollaspingToolbarLayout ISN'T ne se collaspant pas.

13
Fung LAM

Vous devez désactiver le défilement imbriqué par programme. Cela ne semble pas fonctionner correctement si cela est fait en XML.

recyclerView.setNestedScrollingEnabled(false);
34
tachyonflux

C'est le problème le plus courant lors de l'utilisation de recyclerview dans nestedscrollview.

J'ai résolu ce problème en ajoutant les lignes suivantes dans XML.

<Android.support.v7.widget.RecyclerView
            Android:id="@+id/recycler_view_comments"
            Android:layout_width="match_parent"
            Android:layout_height="wrap_content"
            Android:nestedScrollingEnabled="false"
            app:layout_behavior="@string/appbar_scrolling_view_behavior" />
3
SAM

Salut si ça t'intéresse, j'ai créé un LayoutManager qui devrait résoudre ton problème.

public class ExpansiveLayoutManager extends LinearLayoutManager {

private int[] mMeasuredDimension = new int[2];

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

public ExpansiveLayoutManager(Context context, int orientation, boolean reverseLayout) {
    super(context, orientation, reverseLayout);
}

public ExpansiveLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
    super(context, attrs, defStyleAttr, defStyleRes);
}

@Override
public boolean canScrollVertically() {
    return false;
}

@Override
public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state,
                      int widthSpec, int heightSpec) {
    final int widthMode = View.MeasureSpec.getMode(widthSpec);
    final int heightMode = View.MeasureSpec.getMode(heightSpec);
    final int widthSize = View.MeasureSpec.getSize(widthSpec);
    final int heightSize = View.MeasureSpec.getSize(heightSpec);

    int width = 0;
    int height = 0;
    for (int i = 0; i < getItemCount(); i++) {
        measureScrapChild(recycler, i,
                View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
                View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
                mMeasuredDimension);

        if (getOrientation() == HORIZONTAL) {
            width = width + mMeasuredDimension[0];
            if (i == 0) {
                height = mMeasuredDimension[1];
            }
        } else {
            height = height + mMeasuredDimension[1];
            if (i == 0) {
                width = mMeasuredDimension[0];
            }
        }
    }
    switch (widthMode) {
        case View.MeasureSpec.EXACTLY:
            width = widthSize;
        case View.MeasureSpec.AT_MOST:
        case View.MeasureSpec.UNSPECIFIED:
    }

    switch (heightMode) {
        case View.MeasureSpec.EXACTLY:
            height = heightSize;
        case View.MeasureSpec.AT_MOST:
        case View.MeasureSpec.UNSPECIFIED:
    }

    setMeasuredDimension(width, height);
}

private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec,
                               int heightSpec, int[] measuredDimension) {
    View view = recycler.getViewForPosition(position);
    if (view != null) {
        RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams();
        int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec,
                getPaddingLeft() + getPaddingRight(), p.width);
        int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec,
                getPaddingTop() + getPaddingBottom(), p.height);
        view.measure(childWidthSpec, childHeightSpec);
        measuredDimension[0] = view.getMeasuredWidth() + p.leftMargin + p.rightMargin;
        measuredDimension[1] = view.getMeasuredHeight() + p.bottomMargin + p.topMargin;
        recycler.recycleView(view);
    }
}
}

https://github.com/emanuelet/LayoutManagers/blob/master/ExpansiveLayoutManager.Java

2
Emanuele Tonello

Vous n'avez pas besoin de placer votre recyclerView dans NestedScrollView.

<Android.support.v7.widget.RecyclerView
     Android:id="@+id/recycler_movie_suggestion"
     app:layout_behavior="@string/appbar_scrolling_view_behavior"
     Android:layout_width="match_parent"
     Android:layout_height="170dp" />
0
AMarones

Vous n'êtes pas obligé d'utiliser NestedScrollView. Laissez juste LinearLayout ici.

0
Bogdan Ustyak