web-dev-qa-db-ja.com

ScrollView内のRecyclerViewが機能していません

同じレイアウトでRecyclerViewとScrollViewを含むレイアウトを実装しようとしています。

レイアウトテンプレート:

<RelativeLayout>
    <ScrollView Android:id="@+id/myScrollView">
       <unrelated data>...</unrealated data>

           <Android.support.v7.widget.RecyclerView
                Android:layout_width="match_parent"
                Android:layout_height="wrap_content"
                Android:id="@+id/my_recycler_view"
            />
    </ScrollView>


</RelativeLayout>

問題:ScrollViewの最後の要素までスクロールできます

私が試したこと:

  1. ScrollView内のカードビュー(現在のScrollViewRecyclerViewを含む) - RecyclerViewまでカードを見ることができる
  2. 最初の考えは、viewGroupの代わりにRecyclerViewを使ってこのScrollViewを実装することでした。ビュータイプの1つはCardViewですが、ScrollViewとまったく同じ結果が得られました
219
royB

NestedScrollViewの代わりにScrollViewを使用する

NestedScrollViewのリファレンスドキュメント を参照してください。

RecyclerViewrecyclerView.setNestedScrollingEnabled(false);を追加します

527
Yang Peiyong

私はゲームに遅れていることは知っていますが、GoogleがAndroid.support.v7.widget.RecyclerViewを修正した後でもこの問題は依然として存在します

私が今得ている問題は、RecyclerView with layout_height=wrap_contentであり、ScrollView内のすべてのアイテム問題の高さを取得していないことonlyMarshmallowおよびNougat +(API 23、24、25)バージョンで発生します。
(UPDATE:ScrollViewAndroid.support.v4.widget.NestedScrollViewに置き換えると、すべてのバージョンで機能します。テストに失敗しました accepted solution 。デモとしてのgithubプロジェクト。)

別のことを試した後、この問題を修正する回避策を見つけました。

これが私のレイアウト構造の概要です:

<ScrollView>
  <LinearLayout> (vertical - this is the only child of scrollview)
     <SomeViews>
     <RecyclerView> (layout_height=wrap_content)
     <SomeOtherViews>

回避策は、RecyclerViewRelativeLayoutでラップすることです。この回避策を見つけた方法を聞かないでください!!! ¯\_(ツ)_/¯

<RelativeLayout
    Android:layout_width="match_parent"
    Android:layout_height="wrap_content"
    Android:descendantFocusability="blocksDescendants">

    <Android.support.v7.widget.RecyclerView
        Android:layout_width="match_parent"
        Android:layout_height="wrap_content" />

</RelativeLayout>

完全な例は、GitHubプロジェクトで利用できます- https://github.com/amardeshbd/Android-recycler-view-wrap-content

修正の実際を示すデモのスクリーンキャストは次のとおりです。

Screencast

86
Hossain Khan

お勧めは

スクロール可能なビューを別のスクロール可能なビューの中に置いてはいけません。

確かなアドバイスですが、リサイクル業者のビューで固定の高さを設定した場合は正常に機能するはずです。

アダプタ項目のレイアウトの高さがわかっている場合は、RecyclerViewの高さを計算するだけで済みます。

int viewHeight = adapterItemSize * adapterData.size();
recyclerView.getLayoutParams().height = viewHeight;
50
Joakim Engstrom

RecyclerViewに固定の高さを設定しても(私のような)誰かにはうまくいかない場合は、固定高さのソリューションに追加したものがあります。

mRecyclerView.addOnItemTouchListener(new RecyclerView.OnItemTouchListener() {
    @Override
    public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
        int action = e.getAction();
        switch (action) {
            case MotionEvent.ACTION_MOVE:
                rv.getParent().requestDisallowInterceptTouchEvent(true);
                break;
        }
        return false;
    }

    @Override
    public void onTouchEvent(RecyclerView rv, MotionEvent e) {

    }

    @Override
    public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {

    }
});
24
Clans

新しい Android Support Library 23.2 はこの問題を解決し、wrap_contentRecyclerViewの高さとして設定できるようになり、正しく動作します。

Androidサポートライブラリ23.2

23
kevings14

それらが自分自身をスクロールしていない限り、RecyclerViewsはScrollViewsに入れるのが良いです。この場合、それを固定の高さにすることは理にかなっています。

適切な解決策は、RecyclerViewの高さにwrap_contentを使用してから、ラッピングを正しく処理できるカスタムのLinearLayoutManagerを実装することです。

このLinearLayoutManagerをあなたのプロジェクトにコピーしてください: https://github.com/serso/Android-linear-layout-manager/blob/master/lib/src/main/Java/org/solovyev/Android/views/llm/LinearLayoutManager .Java

次にRecyclerViewをラップします。

<Android.support.v7.widget.RecyclerView
    Android:layout_width="match_parent"
    Android:layout_height="wrap_content"/>

そしてそれを次のように設定します。

    RecyclerView list = (RecyclerView)findViewById(R.id.list);
    list.setHasFixedSize(true);
    list.setLayoutManager(new com.example.myapp.LinearLayoutManager(list.getContext()));
    list.setAdapter(new MyViewAdapter(data));

編集:RecyclerViewがScrollViewのタッチイベントを盗むことができるので、これはスクロールの複雑さを引き起こす可能性があります。私の解決策は、単にRecyclerViewを全部捨ててLinearLayoutを使い、プログラム的にサブビューを膨らませてそれらをレイアウトに追加することでした。

15
jcady

ScrollViewの場合、fillViewport=trueを使用して、以下のようにlayout_height="match_parent"を作成して、リサイクルビューを内側に配置することができます。

<ScrollView
    Android:fillViewport="true"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    Android:layout_below="@+id/llOptions">
          <Android.support.v7.widget.RecyclerView
            Android:id="@+id/rvList"
            Android:layout_width="match_parent"
            Android:layout_height="wrap_content"
            />
</ScrollView>

コードによるそれ以上の高さ調整は必要ありません。

14
mustaq

手動でRecyclerViewの高さを計算するのは良くありません。カスタムLayoutManagerを使うのが良いでしょう。

上記の問題の理由は、別のビューの子として追加したときにスクロールがある場合、そのスクロール(ListViewGridViewRecyclerView)が高さの計算に失敗したビューです。そのため、onMeasureメソッドをオーバーライドすると問題が解決します。

デフォルトのレイアウトマネージャを以下のものに置き換えてください。

public class MyLinearLayoutManager extends Android.support.v7.widget.LinearLayoutManager {

private static boolean canMakeInsetsDirty = true;
private static Field insetsDirtyField = null;

private static final int CHILD_WIDTH = 0;
private static final int CHILD_HEIGHT = 1;
private static final int DEFAULT_CHILD_SIZE = 100;

private final int[] childDimensions = new int[2];
private final RecyclerView view;

private int childSize = DEFAULT_CHILD_SIZE;
private boolean hasChildSize;
private int overScrollMode = ViewCompat.OVER_SCROLL_ALWAYS;
private final Rect tmpRect = new Rect();

@SuppressWarnings("UnusedDeclaration")
public MyLinearLayoutManager(Context context) {
    super(context);
    this.view = null;
}

@SuppressWarnings("UnusedDeclaration")
public MyLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
    super(context, orientation, reverseLayout);
    this.view = null;
}

@SuppressWarnings("UnusedDeclaration")
public MyLinearLayoutManager(RecyclerView view) {
    super(view.getContext());
    this.view = view;
    this.overScrollMode = ViewCompat.getOverScrollMode(view);
}

@SuppressWarnings("UnusedDeclaration")
public MyLinearLayoutManager(RecyclerView view, int orientation, boolean reverseLayout) {
    super(view.getContext(), orientation, reverseLayout);
    this.view = view;
    this.overScrollMode = ViewCompat.getOverScrollMode(view);
}

public void setOverScrollMode(int overScrollMode) {
    if (overScrollMode < ViewCompat.OVER_SCROLL_ALWAYS || overScrollMode > ViewCompat.OVER_SCROLL_NEVER)
        throw new IllegalArgumentException("Unknown overscroll mode: " + overScrollMode);
    if (this.view == null) throw new IllegalStateException("view == null");
    this.overScrollMode = overScrollMode;
    ViewCompat.setOverScrollMode(view, overScrollMode);
}

public static int makeUnspecifiedSpec() {
    return View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
}

@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);

    final boolean hasWidthSize = widthMode != View.MeasureSpec.UNSPECIFIED;
    final boolean hasHeightSize = heightMode != View.MeasureSpec.UNSPECIFIED;

    final boolean exactWidth = widthMode == View.MeasureSpec.EXACTLY;
    final boolean exactHeight = heightMode == View.MeasureSpec.EXACTLY;

    final int unspecified = makeUnspecifiedSpec();

    if (exactWidth && exactHeight) {
        // in case of exact calculations for both dimensions let's use default "onMeasure" implementation
        super.onMeasure(recycler, state, widthSpec, heightSpec);
        return;
    }

    final boolean vertical = getOrientation() == VERTICAL;

    initChildDimensions(widthSize, heightSize, vertical);

    int width = 0;
    int height = 0;

    // it's possible to get scrap views in recycler which are bound to old (invalid) adapter entities. This
    // happens because their invalidation happens after "onMeasure" method. As a workaround let's clear the
    // recycler now (it should not cause any performance issues while scrolling as "onMeasure" is never
    // called whiles scrolling)
    recycler.clear();

    final int stateItemCount = state.getItemCount();
    final int adapterItemCount = getItemCount();
    // adapter always contains actual data while state might contain old data (f.e. data before the animation is
    // done). As we want to measure the view with actual data we must use data from the adapter and not from  the
    // state
    for (int i = 0; i < adapterItemCount; i++) {
        if (vertical) {
            if (!hasChildSize) {
                if (i < stateItemCount) {
                    // we should not exceed state count, otherwise we'll get IndexOutOfBoundsException. For such items
                    // we will use previously calculated dimensions
                    measureChild(recycler, i, widthSize, unspecified, childDimensions);
                } else {
                    logMeasureWarning(i);
                }
            }
            height += childDimensions[CHILD_HEIGHT];
            if (i == 0) {
                width = childDimensions[CHILD_WIDTH];
            }
            if (hasHeightSize && height >= heightSize) {
                break;
            }
        } else {
            if (!hasChildSize) {
                if (i < stateItemCount) {
                    // we should not exceed state count, otherwise we'll get IndexOutOfBoundsException. For such items
                    // we will use previously calculated dimensions
                    measureChild(recycler, i, unspecified, heightSize, childDimensions);
                } else {
                    logMeasureWarning(i);
                }
            }
            width += childDimensions[CHILD_WIDTH];
            if (i == 0) {
                height = childDimensions[CHILD_HEIGHT];
            }
            if (hasWidthSize && width >= widthSize) {
                break;
            }
        }
    }

    if (exactWidth) {
        width = widthSize;
    } else {
        width += getPaddingLeft() + getPaddingRight();
        if (hasWidthSize) {
            width = Math.min(width, widthSize);
        }
    }

    if (exactHeight) {
        height = heightSize;
    } else {
        height += getPaddingTop() + getPaddingBottom();
        if (hasHeightSize) {
            height = Math.min(height, heightSize);
        }
    }

    setMeasuredDimension(width, height);

    if (view != null && overScrollMode == ViewCompat.OVER_SCROLL_IF_CONTENT_SCROLLS) {
        final boolean fit = (vertical && (!hasHeightSize || height < heightSize))
                || (!vertical && (!hasWidthSize || width < widthSize));

        ViewCompat.setOverScrollMode(view, fit ? ViewCompat.OVER_SCROLL_NEVER : ViewCompat.OVER_SCROLL_ALWAYS);
    }
}

private void logMeasureWarning(int child) {
    if (BuildConfig.DEBUG) {
        Log.w("MyLinearLayoutManager", "Can't measure child #" + child + ", previously used dimensions will be reused." +
                "To remove this message either use #setChildSize() method or don't run RecyclerView animations");
    }
}

private void initChildDimensions(int width, int height, boolean vertical) {
    if (childDimensions[CHILD_WIDTH] != 0 || childDimensions[CHILD_HEIGHT] != 0) {
        // already initialized, skipping
        return;
    }
    if (vertical) {
        childDimensions[CHILD_WIDTH] = width;
        childDimensions[CHILD_HEIGHT] = childSize;
    } else {
        childDimensions[CHILD_WIDTH] = childSize;
        childDimensions[CHILD_HEIGHT] = height;
    }
}

@Override
public void setOrientation(int orientation) {
    // might be called before the constructor of this class is called
    //noinspection ConstantConditions
    if (childDimensions != null) {
        if (getOrientation() != orientation) {
            childDimensions[CHILD_WIDTH] = 0;
            childDimensions[CHILD_HEIGHT] = 0;
        }
    }
    super.setOrientation(orientation);
}

public void clearChildSize() {
    hasChildSize = false;
    setChildSize(DEFAULT_CHILD_SIZE);
}

public void setChildSize(int childSize) {
    hasChildSize = true;
    if (this.childSize != childSize) {
        this.childSize = childSize;
        requestLayout();
    }
}

private void measureChild(RecyclerView.Recycler recycler, int position, int widthSize, int heightSize, int[] dimensions) {
    final View child;
    try {
        child = recycler.getViewForPosition(position);
    } catch (IndexOutOfBoundsException e) {
        if (BuildConfig.DEBUG) {
            Log.w("MyLinearLayoutManager", "MyLinearLayoutManager doesn't work well with animations. Consider switching them off", e);
        }
        return;
    }

    final RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) child.getLayoutParams();

    final int hPadding = getPaddingLeft() + getPaddingRight();
    final int vPadding = getPaddingTop() + getPaddingBottom();

    final int hMargin = p.leftMargin + p.rightMargin;
    final int vMargin = p.topMargin + p.bottomMargin;

    // we must make insets dirty in order calculateItemDecorationsForChild to work
    makeInsetsDirty(p);
    // this method should be called before any getXxxDecorationXxx() methods
    calculateItemDecorationsForChild(child, tmpRect);

    final int hDecoration = getRightDecorationWidth(child) + getLeftDecorationWidth(child);
    final int vDecoration = getTopDecorationHeight(child) + getBottomDecorationHeight(child);

    final int childWidthSpec = getChildMeasureSpec(widthSize, hPadding + hMargin + hDecoration, p.width, canScrollHorizontally());
    final int childHeightSpec = getChildMeasureSpec(heightSize, vPadding + vMargin + vDecoration, p.height, canScrollVertically());

    child.measure(childWidthSpec, childHeightSpec);

    dimensions[CHILD_WIDTH] = getDecoratedMeasuredWidth(child) + p.leftMargin + p.rightMargin;
    dimensions[CHILD_HEIGHT] = getDecoratedMeasuredHeight(child) + p.bottomMargin + p.topMargin;

    // as view is recycled let's not keep old measured values
    makeInsetsDirty(p);
    recycler.recycleView(child);
}

private static void makeInsetsDirty(RecyclerView.LayoutParams p) {
    if (!canMakeInsetsDirty) {
        return;
    }
    try {
        if (insetsDirtyField == null) {
            insetsDirtyField = RecyclerView.LayoutParams.class.getDeclaredField("mInsetsDirty");
            insetsDirtyField.setAccessible(true);
        }
        insetsDirtyField.set(p, true);
    } catch (NoSuchFieldException e) {
        onMakeInsertDirtyFailed();
    } catch (IllegalAccessException e) {
        onMakeInsertDirtyFailed();
    }
}

private static void onMakeInsertDirtyFailed() {
    canMakeInsetsDirty = false;
    if (BuildConfig.DEBUG) {
        Log.w("MyLinearLayoutManager", "Can't make LayoutParams insets dirty, decorations measurements might be incorrect");
    }
}
}
13
Arun Antoney

これを試して。非常に遅い答えです。しかし、きっと誰かを助けてくれるでしょう。

ScrollviewをNestedScrollViewに設定します

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

あなたのRecyclerviewに

recyclerView.setNestedScrollingEnabled(false); 
recyclerView.setHasFixedSize(false);
9
Ranjith Kumar

更新:入れ子になったスクロールをサポートするNestedScrollViewやRecyclerViewのようなウィジェットがあるので、この答えは現在古くなっています。

スクロール可能なビューを別のスクロール可能なビューの中に入れないでください。

メインレイアウトのリサイクラービューを作成し、そのビューをリサイクラービューの項目として配置することをお勧めします。

この例を見てみましょう。これは、リサイクラビューアダプタ内で複数のビューを使用する方法を示しています。 例へのリンク

7
EC84B4

RecyclerViewNestedScrollViewの内側に入れてrecyclerView.setNestedScrollingEnabled(false);を有効にすると、スクロールはうまく動作するになります。
しかし、問題があります

RecyclerViewリサイクルしないでください

たとえば、RecyclerViewNestedScrollViewまたはScrollView内)には100個の項目があります。
Activityの起動時に、100個のitem 作成されます(100個のitemのonCreateViewHolderonBindViewHolderが同時に呼び出されます)。
たとえば、各アイテムについて、API => activity created - > 100のイメージから大きなイメージをロードします。
それは活動の開始を遅らせ、遅らせる。
可能な解決策
- 複数の型でRecyclerViewを使うことを考えています。

ただし、RecyclerViewの中にごく少数の項目しかなく、リサイクルまたはリサイクルしないがパフォーマンスに大きな影響を与えない場合は、単純にRecyclerViewの中にScrollViewを使用できます

5
Phan Van Linh

この方法を使うことができます:

この行をrecyclerView xmlビューに追加します。

        Android:nestedScrollingEnabled="false"

試してみてください、recyclerviewは柔軟な高さで滑らかにスクロールされます

これが助けになることを願っています。

4
tahaDev

私は同じ問題を抱えていました。それが私が試したことで、うまくいきます。 xmlとJavaコードを共有しています。これが誰かに役立つことを願っています。

これがxmlです

<?xml version="1.0" encoding="utf-8"?>
<ScrollView
    Android:layout_width="match_parent"
    Android:layout_height="wrap_content">
    <LinearLayout
        Android:orientation="vertical"
        Android:layout_width="match_parent"
        Android:layout_height="wrap_content">

        <ImageView
            Android:id="@+id/iv_thumbnail"
            Android:layout_width="match_parent"
            Android:layout_height="200dp" />

        <TextView
            Android:id="@+id/tv_description"
            Android:layout_width="match_parent"
            Android:layout_height="wrap_content"
            Android:text="Description" />

        <Button
            Android:layout_width="match_parent"
            Android:layout_height="wrap_content"
            Android:text="Buy" />

        <TextView
            Android:layout_width="match_parent"
            Android:layout_height="wrap_content"
            Android:text="Reviews" />
        <Android.support.v7.widget.RecyclerView
            Android:id="@+id/rc_reviews"
            Android:layout_width="match_parent"
            Android:layout_height="wrap_content">

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

    </LinearLayout>
</ScrollView>

これが関連するJavaコードです。それは魅力のように働きます。

LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
recyclerView.setLayoutManager(linearLayoutManager);
recyclerView.setNestedScrollingEnabled(false);
2
Zeeshan Shabbir

NestedScrollViewは問題を解決するようです。私はこのレイアウトを使ってテストしました:

<Android.support.v4.widget.NestedScrollView
xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:app="http://schemas.Android.com/apk/res-auto"
xmlns:tools="http://schemas.Android.com/tools"
Android:id="@+id/activity_main"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
>

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

    <TextView
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content"
        Android:text="@string/dummy_text"
        />

    <Android.support.v7.widget.CardView
        Android:layout_width="match_parent"
        Android:layout_height="wrap_content"
        Android:layout_marginLeft="16dp"
        Android:layout_marginRight="16dp"
        >
        <Android.support.v7.widget.RecyclerView
            Android:id="@+id/recycler_view"
            Android:layout_width="match_parent"
            Android:layout_height="wrap_content"/>

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

</LinearLayout>

そしてそれは問題なく動作します

2
royB

これがトリックです:

recyclerView.setNestedScrollingEnabled(false);
1
Shylendra Madda

実際のRecyclerViewの主な目的はListViewScrollViewを補うことです。 RecyclerViewScrollViewを含めることで、多くの種類の子を処理できるRecyclerViewのみを持つことをお勧めします。

0
Samer

パーティーに遅刻して申し訳ありませんが、それはあなたが言及したケースのために完璧に動作する別の解決策があるようです。

リサイクラビューをリサイクラビュー内で使用する場合、それは完璧に動作するようです。私は個人的に試してみましたが、遅くもぎくしゃくも全くしていないようです。これが良い習慣であるかどうかはわかりませんが、複数のリサイクラービューをネストすると、ネストしたスクロールビューでさえ遅くなります。しかしこれはうまくいくようです。試してみてください。ネスティングはこれで完全にうまくいくと確信しています。

0

CustomLayoutManagerを使用してRecyclerView Scrollingを無効にしました。また、WrapContentとしてRecycler Viewを使用しないでください。0dp、Weight = 1として使用してください。

public class CustomLayoutManager extends LinearLayoutManager {
    private boolean isScrollEnabled;

    // orientation should be LinearLayoutManager.VERTICAL or HORIZONTAL
    public CustomLayoutManager(Context context, int orientation, boolean isScrollEnabled) {
        super(context, orientation, false);
        this.isScrollEnabled = isScrollEnabled;
    }

    @Override
    public boolean canScrollVertically() {
        //Similarly you can customize "canScrollHorizontally()" for managing horizontal scroll
        return isScrollEnabled && super.canScrollVertically();
    }
}

RecyclerViewでCustomLayoutManagerを使用します。

CustomLayoutManager mLayoutManager = new CustomLayoutManager(getBaseActivity(), CustomLayoutManager.VERTICAL, false);
        recyclerView.setLayoutManager(mLayoutManager);
        ((DefaultItemAnimator) recyclerView.getItemAnimator()).setSupportsChangeAnimations(false); 
        recyclerView.setAdapter(statsAdapter);

UI XML

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    Android:background="@drawable/background_main"
    Android:fillViewport="false">


    <LinearLayout
        Android:id="@+id/contParentLayout"
        Android:layout_width="match_parent"
        Android:layout_height="match_parent"
        Android:orientation="vertical">

        <FrameLayout
            Android:layout_width="match_parent"
            Android:layout_height="wrap_content">

            <edu.aku.family_hifazat.libraries.mpchart.charts.PieChart
                Android:id="@+id/chart1"
                Android:layout_width="match_parent"
                Android:layout_height="wrap_content"
                Android:layout_marginBottom="@dimen/x20dp"
                Android:minHeight="@dimen/x300dp">

            </edu.aku.family_hifazat.libraries.mpchart.charts.PieChart>


        </FrameLayout>

        <Android.support.v7.widget.RecyclerView
            Android:id="@+id/recyclerView"
            Android:layout_width="match_parent"
            Android:layout_height="0dp"
            Android:layout_weight="1">


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


    </LinearLayout>


</ScrollView>
0
Hamza Khan

ScrollView内にRecyclerViewが1行のみを表示している場合。行の高さをAndroid:layout_height="wrap_content"に設定するだけです。

0
SANAT

また、リサイクルビューを円滑にロールバックするためにLinearLayoutManagerをオーバーライドすることもできます。

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

まずNestedScrollViewの代わりにScrollViewを使用し、RecyclerViewNestedScrollViewの内側に配置します。

カスタムレイアウトクラスを使用して画面の高さと幅を測定します。

public class CustomLinearLayoutManager extends LinearLayoutManager {

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

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

@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++) {
        if (getOrientation() == HORIZONTAL) {
            measureScrapChild(recycler, i,
                    View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
                    heightSpec,
                    mMeasuredDimension);

            width = width + mMeasuredDimension[0];
            if (i == 0) {
                height = mMeasuredDimension[1];
            }
        } else {
            measureScrapChild(recycler, i,
                    widthSpec,
                    View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
                    mMeasuredDimension);
            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);
    recycler.bindViewToPosition(view, 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);
    }
}
}

そしてRecyclerViewのactivity/fragmentに以下のコードを実装します。

 final CustomLinearLayoutManager layoutManager = new CustomLinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);

    recyclerView.setLayoutManager(layoutManager);
    recyclerView.setAdapter(mAdapter);

    recyclerView.setNestedScrollingEnabled(false); // Disables scrolling for RecyclerView, CustomLinearLayoutManager used instead of MyLinearLayoutManager
    recyclerView.setHasFixedSize(false);

    recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            super.onScrolled(recyclerView, dx, dy);

            int visibleItemCount = layoutManager.getChildCount();
            int totalItemCount = layoutManager.getItemCount();
            int lastVisibleItemPos = layoutManager.findLastVisibleItemPosition();
            Log.i("getChildCount", String.valueOf(visibleItemCount));
            Log.i("getItemCount", String.valueOf(totalItemCount));
            Log.i("lastVisibleItemPos", String.valueOf(lastVisibleItemPos));
            if ((visibleItemCount + lastVisibleItemPos) >= totalItemCount) {
                Log.i("LOG", "Last Item Reached!");
            }
        }
    });
0
Soni Kumar