ScrollView 내부의 RecyclerView가 작동하지 않습니다


276

동일한 레이아웃에서 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(현재 ScrollView포함 RecyclerView) 내부의 카드보기 -RecyclerView
  2. 초기 생각은 보기 유형 중 하나 가 있는 곳 대신을 viewGroup사용하여 이것을 구현 하는 RecyclerView것이 었습니다 ScrollView. CardView그러나 나는와 동일한 결과를 얻었습니다.ScrollView

이 접근법을 확인하십시오 : stackoverflow.com/a/21878703/684582
Alécio Carvalho

15
이러한 경우 대부분의 간단한 솔루션을 사용하는 것입니다 NestedScrollView그것은 스크롤 문제를 많이 처리로 대신
리처드 르 Mesurier

리차드는 2 월에 답을 주었다. NestedScrollView대신에을 사용하십시오 ScrollView. 그것이 바로 그 목적입니다.
Mike M.

2
나를 위해 아무것도 변경하지 않습니다.
Luke Allison

2
나중에 참조하기 위해 marshmallow / nougat (API 23, 24) 장치 유사한 문제가 발생하는 경우 stackoverflow.com/a/38995399/132121
Hossain Khan

답변:


653

NestedScrollView대신에 사용ScrollView

통과하십시오 NestedScrollView 참조 문서에 대한 자세한 내용은.

그리고 recyclerView.setNestedScrollingEnabled(false);당신의에 추가RecyclerView


24
작동 : android.support.v4.widget.NestedScrollView
Cocorico

7
유지 android:layout_height="wrap_content"ViewHolder에 대한 팽창 레이아웃에 대한
사라 스 바부에게

4
복잡한 레이아웃 NestedScrollView에서는와 달리 지연됩니다 ScrollView. 사용하지 않고 솔루션 검색NestedScrollView
Roman Samoylenko

7
또한 recyclerView.setNestedScrollingEnabled (false) 대신 android : nestedScrollingEnabled = "false"를 XML에 추가 할 수 있습니다.
kostyabakay

2
그것은 나를 위해 일했지만 recyclerView 내부의 항목은 재활용되지 않는다는 것을 명심하십시오.
Mostafa Arian Nejad

102

게임이 늦었지만 Google에서 문제를 해결 한 후에도 문제가 계속 발생합니다. android.support.v7.widget.RecyclerView

지금 얻는 문제는 RecyclerView함께 layout_height=wrap_content내부의 모든 항목이 문제의 높이를 복용하지 ScrollView에만 산들과 누가 + (API 23, 24, 25) 버전에서 발생합니다.
(업데이트 : 모든 버전 ScrollView에서 android.support.v4.widget.NestedScrollView작동하는 것으로 대체 되었습니다 . 테스트 된 솔루션을 놓친 방법이 없습니다 . github 프로젝트에서 데모로 추가했습니다.)

다른 일을 시도한 후이 문제를 해결하는 해결 방법을 찾았습니다.

간단히 말해 내 레이아웃 구조는 다음과 같습니다.

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

해결 방법은을 감싸는 것 RecyclerView입니다 RelativeLayout. 이 해결 방법을 어떻게 찾았는지 묻지 마십시오 !!!¯\_(ツ)_/¯

<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

다음은 수정 사항을 보여주는 데모 스크린 캐스트입니다.

스크린 캐스트


6
고마워요 .. 그것의 도움이 많이 ..하지만 솔루션 후 스크롤이 어려워서 recyclerview.setNestedScrollingEnabled (false); 그리고 지금은 매력처럼 작동합니다.
Sagar Chavada

4
이 방법은 뷰를 재활용합니까? 재활용 할 수백 개의 물체가 있다면 이것은 해킹이 아닙니다.
androidXP 2016 년

1
예, @androidXP가 옳습니다.이 해킹은 긴 목록에 대한 해결책이 아닙니다. 내 유스 케이스는이 :-) 그들 중 하나였다 적은 10보다 내가 다른 해결 방법을 발견하는 방법에 관해서는, 나는 임의의 일을 시도 하였다 목록보기에서 항목을 수정되었습니다
의 Hossain 칸

adnroid marshmallow와 upper에서 내 문제를 해결했습니다. ;)
Amir Ziarati

2
이 솔루션을 사용하면 onBindView가 목록의 모든 항목에 대해 호출되며 이는 recyclerview의 사용 사례가 아닙니다.
thedarkpassenger 2016 년

54

추천하지만

스크롤 가능한 뷰를 다른 스크롤 가능한 뷰 안에 넣지 마십시오.

올바른 조언이지만, 리사이클 뷰에서 고정 높이를 설정하면 제대로 작동합니다.

어댑터 항목 레이아웃의 높이를 알고 있으면 RecyclerView의 높이를 계산할 수 있습니다.

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

10
recyclerview에서 adapterItemSize를 얻는 방법 아이디어가 있습니까?
Krutik

1
그것은 매력처럼 작동합니다! 약간만 수정하면됩니다 : int viewHeight = adapterItemSize * adapterData.size (); recyclerView.getLayoutParams (). height = viewHeight;
Vaibhav Jani

3
adapterItemSize를 찾는 방법은 무엇입니까?
droidster.me

2
@JoakimEngstrom adapterItemSize변수 는 무엇입니까 ?
IgorGanapolsky

1
스크롤 뷰는 자식에 무한 공간을 제공하므로 스크롤 뷰 내부에서 리사이클 뷰를 피하십시오. 이렇게하면 세로 방향으로 무한히 측정 할 수있는 높이로 wrap_content가있는 리사이클 러보기가 발생합니다 (리사이클 러보기의 마지막 항목까지). 스크롤보기에서 재생기보기를 사용하는 대신 다른 항목 유형의 재생기보기 만 사용하십시오. 이 구현에서 스크롤보기의 하위는보기 유형으로 작동합니다. 리사이클 뷰 내에서 이러한 뷰 유형을 처리하십시오.
abhishesh

28

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) {

    }
});

1
실제로 이것은 나를 위해 잘 작동했습니다. 이를 사용하면 스크롤보기를 위아래로 움직일 수 있었고 스크롤을 위해 recyclerview를 선택하면 스크롤보기보다 우선합니다. 팁 주셔서 감사합니다
PGMacDesign 2016 년

1
그것은 나를 위해 일했다. 단지
스크롤 뷰

이 방법은 cyanogenmod 분포에서도 작동합니다. cyanogenmod의 고정 높이 솔루션은 작동하지만 고정 높이가 목록에있는 모든 항목의 절대 높이 인 경우에만 우선적으로 recyclerview를 사용하는 시점을 무시합니다. 공감.
HappyKatz

또한 recyclerView.setNestedScrollingEnabled (false)가 필요했습니다.
Analizer


15

RecyclerView는 스스로 스크롤하지 않는 한 ScrollView에 넣는 것이 좋습니다. 이 경우 고정 높이로 만드는 것이 좋습니다.

올바른 해결책은 wrap_contentRecyclerView 높이 에서 사용 하고 래핑을 올바르게 처리 할 수있는 사용자 정의 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을 사용하여 프로그래밍 방식으로 하위 뷰를 팽창시키고 레이아웃에 추가하는 것입니다.


4
리사이클 러보기에서 setNestedScrollingEnabled (false)를 호출 할 수 없습니까?
Eshaan

14

의 경우 아래와 같이 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>

코드를 통한 추가 높이 조정이 필요하지 않습니다.


v23.2.1을 사용하여 정상적으로 작동하는지 테스트했습니다. recyclerview 위에 레이아웃을 추가하는 데 사용했습니다.
winsontan520

RecyclerView 스크롤과 ScrollView 스크롤이 안됨
Samad

13

RecyclerView수동으로 높이를 계산하는 것은 좋지 않습니다 LayoutManager. 사용자 정의를 사용하는 것이 좋습니다 .

위의 문제에 대한 이유는 그것의 스크롤이있는이다 ( ListView, GridView, RecyclerView) 다른 뷰에서 자식으로 추가가 스크롤이 때의 높이를 계산하는 데 실패했습니다. 따라서 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");
    }
}
}

데이터를 어댑터로 설정할 때이 클래스를 어떻게 호출 할 수 있습니까?
밀라노 가제 라

11

이 시도. 매우 늦은 답변. 그러나 반드시 미래에 누군가를 도와주십시오.

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

8
NestedScrollView 내에서 RecyclerView 사용 항목이 보이지 않아도 목록의 모든 항목에 대해 onBindView를 호출합니다. 그 문제에 대한 해결책이 있습니까?
thedarkpassenger 2016 년

8

업데이트 : 중첩 스크롤을 지원하는 NestedScrollView 및 RecyclerView와 같은 위젯이 있으므로이 답변의 날짜가 만료되었습니다.

스크롤 가능한 뷰를 다른 스크롤 가능한 뷰 안에 넣지 마십시오!

기본 레이아웃 재활용 뷰를 만들고 재활용 뷰의 항목으로 뷰를 배치하는 것이 좋습니다.

이 예제를 살펴보면 리사이클 뷰 어댑터에서 여러 뷰를 사용하는 방법을 보여줍니다. 예제로 연결


하나 이상의 Recycler 가있는 페이지 가 있는데 이것을 설득하는 다른 방법이 있습니까? 더 많은 댓글 을 클릭하면 더 많은 정보를로드하는 인스 타 그램 또는 구글 플레이 부분 댓글 과 같은 것
Ashkan

하나의 리사이클
러로 만들고

6
말도 안 돼요 중첩 된 RecyclerViews를 잘 가질 수 있습니다.
IgorGanapolsky

이 답변은 이제 구식입니다. 중첩 스크롤 가능 뷰를 허용하는 NestedScrollView와 같은 것들이 있습니다. Nested RecyclerViews도 작동합니다.
Corey Horn

7

당신이 넣으면 RecyclerView내부 NestedScrollView및 활성화 recyclerView.setNestedScrollingEnabled(false);, 스크롤을 잘 작동 .
그러나 문제가 있습니다

RecyclerView 재활용하지 마십시오

예를 들어, RecyclerView( NestedScrollView또는 내부 ScrollView)에 100 개의 항목이 있습니다.
Activity출시, 100 항목이 생성됩니다 ( onCreateViewHolderonBindViewHolder100 항목의 같은 시간에 호출됩니다).
예를 들어, 각 항목에 대해 API => 활동 생성-> 100 이미지에서 큰 이미지를로드합니다.
시작 활동이 느리고 지연됩니다.
가능한 해결책 :
- RecyclerView여러 유형을 사용 하는 것에 대해 생각 합니다.

그러나 귀하의 경우에 품목이 몇 개 RecyclerView있고 재활용 또는 재활용 하지 않는 것이 성능에 큰 영향을 미치지 않는 경우 RecyclerView내부 ScrollView를 간단한 용도로 사용할 수 있습니다


ScollView 내부에서도 RecyclerView를 재활용 할 수있는 방법을 보여주십시오. 감사!
Liar

2
@Liar, 현재에 RecyclerView넣은 후 재활용 할 수있는 방법이 없습니다 ScrollView. 재활용을 원한다면 다른 접근 방식을 생각하십시오 (여러 유형의 RecyclerView 사용)
Phan Van Linh

4

이 방법으로 사용할 수 있습니다 :

이 라인을 recyclerView xml 뷰에 추가하십시오.

        android:nestedScrollingEnabled="false"

시도해보십시오 .recyclerview는 유연한 높이로 부드럽게 스크롤됩니다.

이것이 도움이 되었기를 바랍니다.


2

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>

그리고 문제없이 작동합니다


Bro, Scrollview에서 NestedScrollview로 변경 한 후에도 여전히 동일한 문제가 있습니다.
MohanRaj S

mmm ... 코드를 공유 할 수 있습니까? 제로 문제가 없지만 이런 종류의 문제를 알 수는 없습니다
royB

이메일이나 스택 오버플로를 통해 코드를 공유하는 방법
MohanRaj S

2
이 코드를 사용하면 목록에 해당 항목이 표시되지 않더라도 목록의 모든 항목에 대해 onBindView를 호출합니다. 이것은 recyclerview의 목적을 무효화합니다.
thedarkpassenger 2016 년

2

CustomLayoutManager를 사용하여 RecyclerView Scrolling을 비활성화했습니다. Recycler View를 WrapContent로 사용하지 말고 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>

2

나는 같은 문제를 겪고 있었다. 그것이 내가 시도한 것이며 효과가 있습니다. XML과 Java 코드를 공유하고 있습니다. 이것이 누군가를 도울 수 있기를 바랍니다.

여기 XML이 있습니다

<?xml version="1.0" encoding="utf-8"?>

< NestedScrollView
    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>
</NestedScrollView >

다음은 관련 Java 코드입니다. 그것은 매력처럼 작동합니다.

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

RecyclerView 아래의 레이아웃은 어떻습니까?
Tapa 저장

잘 작동합니다. 사용하면됩니다. NestedScrollView스크롤보기 대신
Zeeshan Shabbir

예, NestedScrollView 만 있습니다. 그러나 NestedScrollView + RecycleView가있는 솔루션은 매우 느린 RecyclerView 모집단을 호출합니다 (RecyclerView 이후 첫 번째보기의 Y 위치 계산을 생각합니다)
Tapa Save


0

실제로의 주요 목적은 RecyclerView보상하는 것입니다 ListViewScrollView. 에서 실제로하는 일을하는 대신 : RecyclerViewin a 을 사용하면 많은 유형의 어린이를 처리 할 수 ScrollView있는 RecyclerView것을 사용 하는 것이 좋습니다 .


1
이것은 아이들이 시야 밖으로 스크롤하자마자 가비지 수집 될 수있는 경우에만 작동합니다. mapFragments 또는 streetviews 인 자식이있는 경우 Recyclerview를 스크롤 할 때마다 다시로드해야하므로 의미가 없습니다. 스크롤보기에 포함시킨 다음 하단에 리사이클 러보기를 생성하는 것이 더 합리적입니다.
시몬

1
편리한 ViewHolder에 setIsRecyclable () 거기 @ 사이먼
ernazm

RecyclerView는 ListView를 대체하지만 ScrollView를 대체하지는 않습니다.
cyroxis

이 의견은 더 가치가 있습니다. 그것은 해결책이며, 허용되는 것보다 훨씬 좋습니다.
Kai Wang

0

먼저 NestedScrollView대신 사용 ScrollView하고 RecyclerView내부를 넣어야합니다 NestedScrollView.

사용자 정의 레이아웃 클래스를 사용하여 화면의 높이와 너비를 측정하십시오.

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.

 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

RecyclerView가 ScrollView 내부에 하나의 행만 표시하는 경우 행 높이를로 설정하면 android:layout_height="wrap_content"됩니다.


0

리사이클 러 뷰 롤을 부드럽게 만들기 위해 LinearLayoutManager를 재정의 할 수도 있습니다.

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

0

파티에 늦어서 죄송하지만 언급 한 경우에 완벽하게 작동하는 또 다른 솔루션이있는 것 같습니다.

리사이클 뷰에서 리사이클 뷰를 사용하면 완벽하게 작동하는 것 같습니다. 나는 개인적으로 그것을 시도하고 사용했으며, 느려짐과 육포가 전혀없는 것 같습니다. 이제 이것이 좋은 방법인지 아닌지는 확실하지 않지만 여러 재활용 뷰를 중첩하면 중첩 된 스크롤 뷰조차 느려집니다. 그러나 이것은 잘 작동하는 것 같습니다. 시도해주세요. 나는 이것으로 중첩이 완벽하게 잘 될 것이라고 확신합니다.


0

이 문제를 해결하기위한 또 다른 방법은 사용하는 것입니다 ConstraintLayout내부 ScrollView:

<ScrollView>
  <ConstraintLayout> (this is the only child of ScrollView)
    <...Some Views...>
    <RecyclerView> (layout_height=wrap_content)
    <...Some Other Views...>

그러나 나는 여전히 androidx.core.widget.NestedScrollView Yang Peiyong이 제안한 접근 방식을 고수 할 것 입니다.


-2

** 나를 위해 일한 솔루션
wrap_content로 높이가 NestedScrollView를 사용하십시오.

<br> RecyclerView 
                android:layout_width="match_parent"<br>
                android:layout_height="wrap_content"<br>
                android:nestedScrollingEnabled="false"<br>
                  app:layoutManager="android.support.v7.widget.LinearLayoutManager"
                tools:targetApi="lollipop"<br><br> and view holder layout 
 <br> android:layout_width="match_parent"<br>
        android:layout_height="wrap_content"

// 행 내용이 여기에 간다


비슷한 답변에 대한 일부 의견에 따르면 중첩 스크롤을 비활성화하면 RecyclerView를 사용하는 목적이 무효화됩니다. 즉, 뷰를 재활용하지 않습니다. 확인 방법을 잘 모르겠습니다.
jk7

1
nestedScrollingEnabled = "false"를 설정하면 적어도 내 설정 (NestedScrollView 내부의 RecyclerView)에서 RecyclerView가 뷰를 재활용하지 않습니다. RecyclerListener를 RecyclerView에 추가하고 onViewRecycled () 메서드 내에 중단 점을 설정하여 확인합니다.
jk7
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.