티스토리 뷰

반응형

Stack Overflow에 자주 검색, 등록되는 문제들과 제가 개발 중 찾아 본 문제들 중에서 나중에도 찾아 볼 것 같은 문제들을 정리하고 있습니다.

Stack Overflow에서 가장 먼저 확인하게 되는 가장 높은 점수를 받은 Solution과 현 시점에 도움이 될 수 있는 가장 최근에 업데이트(최소 점수 확보)된 Solution을 각각 정리하였습니다.

 

아래 word cloud를 통해 이번 포스팅의 주요 키워드를 미리 확인하세요.

How do I make WRAP_CONTENT work on a RecyclerView

RecyclerView에서 WRAP_CONTENT를 사용하려면 어떻게 해야하나요

 문제 내용 

I have a DialogFragment that contains a RecyclerView (a list of cards).

저는 카드 목록인 RecyclerView를 포함하는 DialogFragment를 가지고 있습니다.

 

Within this RecyclerView are one or more CardViews that can have any height.

이 RecyclerView 안에는 높이가 다른 하나 이상의 CardView가 있을 수 있습니다.

 

I want to give this DialogFragment the correct height based on the CardViews that are contained within.

저는 이 DialogFragment의 높이를 포함된 CardView에 기반하여 올바른 높이로 지정하고 싶습니다.

 

Normally this would be simple, I would set wrap_content on the RecyclerView like this.

보통 이것은 간단합니다. 다음과 같이 RecyclerView에 wrap_content를 설정하면 됩니다.
<android.support.v7.widget.RecyclerView ...
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/recycler_view"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"   
    android:clickable="true"   
    android:scrollbars="vertical" >

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

 

Because I am using a RecyclerView this does not work:

RecyclerView를 사용하기 때문에 이것은 작동하지 않습니다.

 

https://issuetracker.google.com/issues/37001674

해당 링크는 구글이 관리하는 이슈 트래커 페이지입니다.

 

and

그리고

 

Nested Recycler view height doesn't wrap its content

중첩된 리사이클러뷰의 높이가 내용물을 감싸지 않습니다.

 

On both of these pages people suggest to extend LinearLayoutManager and to override onMeasure()

이 두 페이지에서는 onMeasure()를 재정의하는 LinearLayoutManager를 확장하는 것을 제안하고 있습니다.

 

I first used the LayoutManager that someone provided in the first link:

처음에는 첫 번째 링크에서 제공된 LayoutManager를 사용했습니다.
public static class WrappingLayoutManager extends LinearLayoutManager {

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

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

            measureScrapChild(recycler, 0,
                    View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
                    View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
                    mMeasuredDimension);

            int width = mMeasuredDimension[0];
            int height = mMeasuredDimension[1];

            switch (widthMode) {
                case View.MeasureSpec.EXACTLY:
                case View.MeasureSpec.AT_MOST:
                    width = widthSize;
                    break;
                case View.MeasureSpec.UNSPECIFIED:
            }

            switch (heightMode) {
                case View.MeasureSpec.EXACTLY:
                case View.MeasureSpec.AT_MOST:
                    height = heightSize;
                    break;
                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();
                measuredDimension[1] = view.getMeasuredHeight();
                recycler.recycleView(view);
            }
        }
    }

 

However this did not work because

하지만 이것은 작동하지 않았습니다.

 

heightSize = View.MeasureSpec.getSize(heightSpec);

 

returns a very large value that appear to be related to match_parent.

해당 함수는 match\_parent와 관련된 매우 큰 값을 반환합니다.

 

By commenting height = heightSize; (in the second switch case) I managed to make the height work but only if a TextView child inside the CardView does not wrap its own text (a long sentence).

CardView 내부에 있는 TextView가 텍스트를 감싸지 않은 경우(긴 문장이 없는 경우), heightSize를 그대로 적용하여 높이를 설정할 수 있었습니다. 두 번째 switch 케이스에서 height = heightSize; 주석 처리를 함으로써 높이를 적용할 수 있었습니다.

 

As soon as that TextView wraps it's own text the height SHOULD increase but it doesn't. It calculated the height for that long sentence as a single line, not a wrapped line (2 or more).

해당 TextView의 텍스트가 한 줄이 아니라 여러 줄이 될 경우, 높이가 늘어나야 하지만 그렇지 않습니다. 긴 문장에 대해 높이를 계산할 때 해당 텍스트뷰의 높이를 한 줄로 계산하고 있기 때문입니다.

 

Any advice on how I should improve this LayoutManager so my RecyclerView works with WRAP_CONTENT?

어떻게하면 RecyclerView가 WRAP_CONTENT와 함께 작동하는 LayoutManager를 개선할 수 있는지에 대한 조언이 있나요?

 

Edit: This layout manager might work for most people, but it still has problems with scrolling and calculating heights of wrapping textviews

편집: 이 레이아웃 매니저는 대부분의 사람들에게 작동할 수 있지만, 스크롤링 및 텍스트 래핑의 높이 계산에 문제가 있을 수 있습니다.
public class MyLinearLayoutManager extends LinearLayoutManager {

public MyLinearLayoutManager(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++) {
        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);
        }
    }
}

 

 

 높은 점수를 받은 Solution 

From Android Support Library 23.2.1 update, all WRAP_CONTENT should work correctly.

안드로이드 서포트 라이브러리 23.2.1 업데이트부터는 모든 WRAP_CONTENT가 올바르게 작동해야 합니다.

 

Please update version of a library in gradle file OR to further :

gradle 파일에서 라이브러리 버전을 업데이트하거나, 더 나은 방법으로:
compile 'com.android.support:recyclerview-v7:23.2.1'

 

solved some issue like Fixed bugs related to various measure-spec methods

해결된 문제들 중 일부는 측정 지정(spec) 방법과 관련된 버그를 수정했습니다.

 

Check http://developer.android.com/tools/support-library/features.html#v7-recyclerview

(http://developer.android.com/tools/support-library/features.html#v7-recyclerview%EB%A5%BC) 확인하세요.

 

you can check Support Library revision history

Support Library의 변경 내역을 확인할 수 있습니다.

 

 

 

 가장 최근 달린 Solution 

Simply put your RecyclerView inside a NestedScrollView. Works perfectly

간단히 말해서 RecyclerView를 NestedScrollView 안에 넣으면 완벽하게 작동합니다.
<android.support.v4.widget.NestedScrollView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="10dp"
                android:layout_marginBottom="25dp">
                <android.support.v7.widget.RecyclerView
                    android:id="@+id/kliste"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent" />
            </android.support.v4.widget.NestedScrollView>

 

 

출처 : https://stackoverflow.com/questions/27475178/how-do-i-make-wrap-content-work-on-a-recyclerview

반응형
댓글
공지사항
최근에 올라온 글