web-dev-qa-db-ja.com

RecyclerviewビューはsetNestedScrollingEnabledで機能せず、ビューもリサイクルされません

私は2つの問題に直面しています:

  1. スクロールリスナーが機能しない
  2. RecyclerViewは、NestedScrollViewにアタッチされている場合、ビューをリサイクルすることはありません。 ScrollView内の線形レイアウトのように機能します。大量のメモリを使用し、ラグを作成します。

リサイクラービュー内にフラグメントを配置できないため、リサイクラービューの上にYouTubeプレーヤーフラグメントを添付しています。私のコードでは、フレームレイアウトがあることがわかります。

私のレイアウトは次のようになります。

_    <Android.support.v4.widget.NestedScrollView xmlns:Android="http://schemas.Android.com/apk/res/Android"
    xmlns:app="http://schemas.Android.com/apk/res-auto"
    Android:id="@+id/nestedScroll"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    Android:background="#ffffff"
    Android:orientation="vertical">


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

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

            <FrameLayout               
                Android:layout_width="match_parent"
                Android:layout_height="240dp"
                Android:layout_alignParentTop="true"/>





        </LinearLayout>


        <Android.support.v7.widget.RecyclerView
            Android:id="@+id/recycler_view"
            Android:layout_width="match_parent"
            Android:layout_height="wrap_content"
            Android:layout_below="@+id/youtube_layout"
            Android:visibility="visible"/>




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

スクロールリスナーを使用してさらにアイテムをロードしたいので、次のことを試しました。

_@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
    Log.i(TAG, "onScrolled: ");
    // bail out if scrolling upward or already loading data
    if (dy < 0 || dataLoading.isDataLoading()) return;

    final int visibleItemCount = recyclerView.getChildCount();
    final int totalItemCount = layoutManager.getItemCount();
    final int firstVisibleItem = layoutManager.findFirstVisibleItemPosition();

    if ((totalItemCount - visibleItemCount) <= (firstVisibleItem )) {
        onLoadMore();
    }


}
_

しかし、layoutManager.findFirstVisibleItemPosition()==0なので機能せず、recyclerview.setNestedScrollingEnabled(false)を設定してから_onScrolled never called twice_以上になります

だから私はこのようにonBindViewで試しました

_   public void onBindViewHolder(RecyclerView.ViewHolder customViewHolder, int i) {
    Log.w("d","inside bind view");

    if(i>=getItemCount()-1  &&   !datamanager.isDataLoading()){
        datamanager.loadmoreData();
    }
_

しかし、recylerviewは、スクロールを開始する前に一度にすべてのビューをバインドするため、この方法も機能しません。

14
Asthme

リサイクラービューは、ネストされたスクロールビューにアタッチされている場合、ビューをリサイクルすることはありません。スクロールビュー内の線形レイアウトで設定されたとおりに機能します。巨大なメモリを作成し、画面を遅らせます。

丁度。 RecyclerViewを別のスクロールビュー内に配置することはできません。

ラッピングビューはRecyclerViewの全高を知る必要があり、RecyclerViewはそのアイテムのすべてallを測定してレイアウトすることによってのみ全高を知ることができるため、機能しません。

これを修正する方法は?

RecyclerViewを別のスクロールビュー内に配置しないでください。

ヘッダーまたはフッターが必要な場合は、それをRecyclerViewに追加し、RecyclerViewに表示させる必要があります。 ScrollViewを削除し、ヘッダーをRecyclerViewの内部に移動します。

技術的には、RecyclerView内にフラグメントをロードすることも可能ですが、これを正しく機能させるには少し注意が必要です。

プロセスを容易にするライブラリもたくさんあります。私の個人的なお気に入りは Epoxy AirBnb製ですが、 Groupie などもあります。

11
David Medenjak

私はこのような状況に対処しました。 recyclerviewがあります。リサイクラービューにはビューページャーがあります。ビューページャーにはフラグメントがあり、フラグメント内にリサイクラービューがあります。

完全にスクロールするには、タッチをハックする必要があります。

private boolean interceptTouch = true;
    private static final int MIN_DISTANCE = 200;
    private float downX = 0, downY = 0, moveX = 0, moveY = 0, upX = 0, upY;

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

    public TouchInterceptRecyclerView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }


    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        if (getRvTop() == 0) {
            onTouchEvent(ev);
        }
        return interceptTouch;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                downX = event.getX();
                downY = event.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                moveX = event.getX();
                moveY = event.getY();
                break;
            case MotionEvent.ACTION_UP:
                upX = event.getX();
                upY = event.getY();
                break;
        }
        float deltaX = upX - downX;

        if (getViewTop() == 0 && moveY > downY && Math.abs(moveY - downY) > MIN_DISTANCE) {  // moving down
            interceptTouch = true;
        }else if (Math.abs(deltaX) > MIN_DISTANCE) {
            if (upX > downX) {    // Left to Right swipe action
                interceptTouch = false;
            }else {    // Right to left swipe action
                interceptTouch = false;
            }
        } else {  // screen tap
            interceptTouch = false;
        }
        return super.onTouchEvent(event);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        return super.dispatchTouchEvent(ev);
    }

    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        super.onScrollChanged(l, t, oldl, oldt);
    }

    @Override
    public void onScrolled(int dx, int dy) {
        if (getViewTop() <= 0) {
            interceptTouch = false;            // dispatch the touch to child when reached top
        } else {
            interceptTouch = true;           // do not dispatch the touch event
        }
        super.onScrolled(dx, dy);
    }

    public int getViewTop() {
        int top = 0;
        View v = this.getChildAt(1);
        if (v == null) {
            v = this.getChildAt(0);
        }
        if (v != null && v instanceof LinearLayout) {
            top = v.getTop();
        }
        return top;
    }

    public int getRvTop() {
        int top = -1;
        View v = this.getChildAt(1);
        if (v == null) {
            v = this.getChildAt(0);
        }
        if (v != null && v instanceof LinearLayout) {

            ViewPager vp = (ViewPager) v.findViewById(R.id.single_tribe_pager);
            if (vp != null) {
                int currentPos = vp.getCurrentItem();
                RecyclerView rv = (RecyclerView) vp.findViewWithTag("recyclerview" + currentPos);
                if (rv != null) {
                    View v1 = rv.getChildAt(0);
                    if (v1 != null && v1 instanceof CardView) {
                        top = v1.getTop() - ResourceUtils.getDimensionPixelOffset(R.dimen.padding_20);   // deducting 20 as we have give top margin as 20 to the top layout
                    }
                }
            }
        }
        return top;
    }
0
Harsh