선택된 항목을 맨 위에 표시하려면 RecyclerView를 스크롤하십시오.


216

RecyclerView선택한 항목을 맨 위에 표시 하기 위해 a를 스크롤하는 방법을 찾고 있습니다.

A의 ListView내가 사용하여 해당 작업을 수행 할 수 있었다 scrollTo(x,y)및 필요를 중심으로 될 수있는 요소의 상단을 받고.

다음과 같은 것 :

@Override
public void onItemClick(View v, int pos){
    mylistView.scrollTo(0, v.getTop());
}

문제는 메서드를 RecyclerView사용할 때 오류가 반환 된다는 scrollTo것입니다.

RecyclerView는 절대 위치로 스크롤을 지원하지 않습니다

a RecyclerView를 스크롤 하여 선택한 항목을보기 상단에 놓을 수 있습니까?

답변:


406

LinearLayoutManager또는 Staggered를 사용하는 경우 GridLayoutManager각각에는 scrollToPositionWithOffset 메소드가 있으며,이 위치는 시작 위치에서 항목 시작 위치와 위치 오프셋을 가져옵니다. RecyclerView필요한 것을 달성하는 것처럼 보입니다 (오프셋을 0으로 설정) 상단에 맞춰야합니다).

예를 들어 :

//Scroll item 2 to 20 pixels from the top
linearLayoutManager.scrollToPositionWithOffset(2, 20);

34
누구나 RecyclerView의 스크롤 위치를 복원하기 위해 이것이 필요한 경우 스크롤 위치를 저장하는 방법입니다 (scrollToPositionWithOffset 메소드의 두 인수). int index = linearLayoutManager.findFirstVisibleItemPosition (); 보기 v = linearLayoutManager.getChildAt (0); int top = (v == null)? 0 : (v.getTop ()-linearLayoutManager.getPaddingTop ());
DominicM

내가 이것에 대해 얻지 못하는 것은 scrollToPosition을 호출 할 때입니다 . 선택 리스너가 개별 뷰에있는 경우 RecyclerView 객체 (scrolToPosition을 호출 할 수있는 레이아웃 관리자에 액세스 할 수있는)는 항목이 선택되었다는 것을 어떻게 알 수 있습니까?
Nonos

@Nonos 먼저 RecylerView.setLayoutManager ()에서 사용하는 LayoutManager를 저장 한 다음 직접 액세스 할 수 있습니다. 다음과 같이 : LinearLayoutManager llm = new LinearLayoutManager (this); mRecyclerView.setLayoutManager (llm); ... (나중에 코드) ... llm.scrollToPositionWithOffset (2, 20);
Niraj

19
맨 위로 "부드럽게"스크롤하려면 어떻게해야합니까?
Tiago

@Tiago, 나는 그것을 가지고 놀지 않았지만,이 3 가지 기사 시리즈가 도움이 될 수 있습니다 : blog.stylingandroid.com/scrolling-recyclerview-part-1
Niraj

93

수직 LinearLayout Manager를 찾고 있다면 사용자 정의를 사용하여 부드러운 스크롤을 얻을 수 있습니다 LinearSmoothScroller.

import android.content.Context;
import android.graphics.PointF;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.LinearSmoothScroller;
import android.support.v7.widget.RecyclerView;

public class SnappingLinearLayoutManager extends LinearLayoutManager {

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

    @Override
    public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state,
                                       int position) {
        RecyclerView.SmoothScroller smoothScroller = new TopSnappedSmoothScroller(recyclerView.getContext());
        smoothScroller.setTargetPosition(position);
        startSmoothScroll(smoothScroller);
    }

    private class TopSnappedSmoothScroller extends LinearSmoothScroller {
        public TopSnappedSmoothScroller(Context context) {
            super(context);

        }

        @Override
        public PointF computeScrollVectorForPosition(int targetPosition) {
            return SnappingLinearLayoutManager.this
                    .computeScrollVectorForPosition(targetPosition);
        }

        @Override
        protected int getVerticalSnapPreference() {
            return SNAP_TO_START;
        }
    }
}

재활용보기에서 레이아웃 관리자 인스턴스를 사용하면 호출 recyclerView.smoothScrollToPosition(pos);하면 선택된 위치로 부드럽게 스크롤하여 재활용보기 상단으로 이동합니다.


1
정말 유용한 답변입니다! 또한 getHorizontalSnapPreference()수평 목록의 TopSnappedSmoothScroller에서 재정의 합니다.
Juan Saravia

6
나는 이것이 남은 부분을 채우기에 충분한 후에 / 아래에있는 항목에 대해서만 작동한다는 것을 관찰하는 것이 맞 RecyclerView습니까? -에 관계없이이 마지막 항목에 대한 작동하지 않습니다 어떤 말을하는 것입니다 에만 스크롤 항목이 하단에 표시됩니다하지만 모든 방법을 이동하지 않을 때까지. 이것을 달성하는 방법에 대한 아이디어가 있습니까? (이 문제를 해결하기 위해 사용자 정의 패딩을 설정 했지만 실제로 옳지 않은 것 같습니다 ...)SNAP_TO_STARTRecyclerViewRecyclerView
david.mihola


때로는 항목 선량이 집중되면 항목보기에 초점을 맞출 수 있습니다.
YLS

1
@ david.mihola '올바른'방법을 찾았습니까? 나는 recyclerview에 사용자 정의 패딩을 설정했지만 이상한 문제가 있습니다 ...
bernardo.g


28

전화하면 recyclerview.scrollToPosition(position)됩니다. 괜찮아!

어댑터에서 호출하려면 어댑터에 메소드 getRecyclerview()를 구현하는 것보다 어댑터에 recyclerview 인스턴스 또는 recyclerview를 포함하는 활동 또는 단편을 갖도록하십시오.

나는 그것이 당신을 도울 수 있기를 바랍니다.


2
이것은 나를 위해 일했다-recyclerView.scrollToPosition (0); 맨 위에 올려 놔
Ray Hunter

2
작동하지 않으면 linearLayoutManager.scrollToPositionWithOffset (pos, 0)을 사용해야합니다.
Anil Ugale

@Anil Ugale 그건 말도 안됩니다. 물론 작동합니다. RecyclerView에 모든 LayoutManager를 사용할 수 있습니다. 나중에 스크롤 할 때 왜 신경 써야합니까? 네가 잘못한 것 같아 Recyclerview.scrollToPosition (position)은 LayoutManager.scrollToPosition (position)을 호출하는 편리한 방법입니다.
놀라운 01 1

1
@TheincredibleJan 모든 경우에 작동하지는 않습니다. layoutManager는 일반적으로 정보에 대한 스크롤을 책임집니다.
Mohammed

11

스피드 레귤레이터와 동일

public class SmoothScrollLinearLayoutManager extends LinearLayoutManager {
private static final float MILLISECONDS_PER_INCH = 110f;
private Context mContext;

public SmoothScrollLinearLayoutManager(Context context,int orientation, boolean reverseLayout) {
    super(context,orientation,reverseLayout);
    mContext = context;
}

@Override
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state,
                                   int position) {
    RecyclerView.SmoothScroller smoothScroller = new TopSnappedSmoothScroller(recyclerView.getContext()){
        //This controls the direction in which smoothScroll looks for your view
        @Override
        public PointF computeScrollVectorForPosition(int targetPosition) {
            return new PointF(0, 1);
        }

        //This returns the milliseconds it takes to scroll one pixel.
        @Override
        protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
            return MILLISECONDS_PER_INCH / displayMetrics.densityDpi;
        }
    };
    smoothScroller.setTargetPosition(position);
    startSmoothScroll(smoothScroller);
}


private class TopSnappedSmoothScroller extends LinearSmoothScroller {
    public TopSnappedSmoothScroller(Context context) {
        super(context);

    }

    @Override
    public PointF computeScrollVectorForPosition(int targetPosition) {
        return SmoothScrollLinearLayoutManager.this
                .computeScrollVectorForPosition(targetPosition);
    }

    @Override
    protected int getVerticalSnapPreference() {
        return SNAP_TO_START;
    }
}
}

8

나를 위해 일한 것을 시원하게 해보십시오!

변수 만들기 private static int displayedposition = 0;

이제 활동에서 RecyclerView의 위치를 ​​찾으십시오.

myRecyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
            }

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

                LinearLayoutManager llm = (LinearLayoutManager) myRecyclerView.getLayoutManager();


                displayedposition = llm.findFirstVisibleItemPosition();


            }
        });

이 문장을 원하는 곳에 배치하여 이전 사이트를보기에 표시하십시오.

LinearLayoutManager llm = (LinearLayoutManager) mRecyclerView.getLayoutManager();
        llm.scrollToPositionWithOffset(displayedposition , youList.size());

글쎄, 그것은 나를 위해 잘 작동 \ o /


7

이 메소드를 간단히 호출하십시오.

((LinearLayoutManager)recyclerView.getLayoutManager()).scrollToPositionWithOffset(yourItemPosition,0);

대신에:

recyclerView.scrollToPosition(yourItemPosition);

"대신에"? Distwo는 "scrollToPosition"에 대해 언급하지 않았습니다. 그가 그것을 사용했다면 아무런 문제가 없었을 것입니다. 의도 한대로 scrollToPosition ().
놀라운 1

1
이상하게도 scrollToPositionWithOffset을 사용하면 저에게 효과적이며 recyclerview.scrollToPosition이 작동하지 않습니다. 비록 Amir에게 RecyclerView를 recyclerview로 변경하도록 요청합니다. 왜냐하면 메소드가 정적이며 그렇지 않기 때문입니다.
Mohit

6

버튼을 클릭하면 RecyclerView를 새로 고친 후 스크롤 위치를 복원하기 위해 수행 한 작업 :

if (linearLayoutManager != null) {

    index = linearLayoutManager.findFirstVisibleItemPosition();
    View v = linearLayoutManager.getChildAt(0);
    top = (v == null) ? 0 : (v.getTop() - linearLayoutManager.getPaddingTop());
    Log.d("TAG", "visible position " + " " + index);
}

else{
    index = 0;
}

linearLayoutManager = new LinearLayoutManager(getApplicationContext());
linearLayoutManager.scrollToPositionWithOffset(index, top);

linearLayoutManager 객체를 만들기 전에 맨 처음부터 보이는 항목의 오프셋을 가져 와서 인스턴스화 한 후 LinearLayoutManager 객체의 scrollToPositionWithOffset을 호출했습니다.


6

왜 내가 가장 좋은 답을 찾지 못했는지 정말 모르겠습니다.

recyclerView.smoothScrollToPosition(position);

오류 없음

애니메이션을 만듭니다


이것을 어디에 활동이나 어댑터에 넣을 것인가?
Arnold Brown

3

특정 위치에서 스크롤
하면 많은 도움이되었습니다. 클릭 청취자에 의해 당신은 당신의 어댑터에서 위치를 얻을 수 있습니다

layoutmanager.scrollToPosition(int position);

3
If you want to scroll automatic without show scroll motion then you need to write following code:

**=> mRecyclerView.getLayoutManager().scrollToPosition(position);**

If you want to display scroll motion then you need to add following code.
=>Step 1: You need to declare SmoothScroller.

RecyclerView.SmoothScroller smoothScroller = new
                LinearSmoothScroller(this.getApplicationContext()) {
                    @Override
                    protected int getVerticalSnapPreference() {
                        return LinearSmoothScroller.SNAP_TO_START;
                    }
                };

=>step 2: You need to add this code any event you want to perform scroll to specific position.
=>First you need to set target position to SmoothScroller.

**smoothScroller.setTargetPosition(position);**

=>Then you need to set SmoothScroller to LayoutManager.
                        **mRecyclerView.getLayoutManager().startSmoothScroll(smoothScroller);**

3

어떤 대답도 맨 위에 마지막 항목을 표시하는 방법을 설명하지 않습니다. 따라서 답변은 여전히 ​​위 또는 아래에 충분한 항목이 남아있는 항목에 대해서만 작동합니다 RecyclerView. 예를 들어, 59 개의 요소가 있고 56 번째 요소가 선택된 경우 아래 그림과 같이 맨 위에 있어야합니다.

RecyclerView-요소 56이 선택되었습니다 우리는 사용하여 이러한 경우 처리 할 수 linearLayoutManager.scrollToPositionWithOffset(pos, 0)로 및 추가 논리를 AdapterRecyclerView(마지막 항목이 표시되어 있지 않은 경우는 충분한 공간 채우기가 있다는 뜻 마지막 항목 아래의 사용자 정의 마진을 추가하여 - RecyclerView). 사용자 정의 여백은 루트 뷰 높이와 항목 높이의 차이 일 수 있습니다. 그래서, 당신 Adapter을위한 RecyclerView같이 보일 것이다는 다음과 같습니다 :

...
@Override
public void onBindViewHolder(ViewHolder holder, final int position) {
    ...

    int bottomHeight = 0;
    int itemHeight = holder.itemView.getMeasuredHeight();
    // if it's the last item then add a bottom margin that is enough to bring it to the top
    if (position == mDataSet.length - 1) {
        bottomHeight = Math.max(0, mRootView.getMeasuredHeight() - itemHeight);
    }
    RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)holder.itemView.getLayoutParams();
    params.setMargins(0, 0, params.rightMargin, bottomHeight);
    holder.itemView.setLayoutParams(params);

    ...
} 
...

2

제 경우에는 이와 RecyclerView같은 패딩 탑이 있습니다.

<android.support.v7.widget.RecyclerView
     ...
     android:paddingTop="100dp"
     android:clipToPadding="false"
/>

그런 다음 항목을 맨 위로 스크롤하려면

recyclerViewLinearLayoutManager.scrollToPositionWithOffset(position, -yourRecyclerView.getPaddingTop());

1

당신 LayoutManager이 그것을 LinearLayoutManager사용 scrollToPositionWithOffset(position,0);하고 있다면 그것은 당신의 아이템을 목록에서 가장 먼저 보이는 아이템으로 만들 것입니다. 그렇지 않으면, 당신은 사용할 수있는 smoothScrollToPositionRecyclerView직접.

아래 코드를 사용하여 끝났습니다.

 RecyclerView.LayoutManager layoutManager = mainList.getLayoutManager();
        if (layoutManager instanceof LinearLayoutManager) {
            // Scroll to item and make it the first visible item of the list.
            ((LinearLayoutManager) layoutManager).scrollToPositionWithOffset(position, 0);
        } else {
            mainList.smoothScrollToPosition(position);
        }

-2

아래 코드를 사용하여 항목 (thisView)을 맨 위로 부드럽게 스크롤합니다.
다른 높이의 뷰를 가진 GridLayoutManager에서도 작동합니다.

View firstView = mRecyclerView.getChildAt(0);
int toY = firstView.getTop();
int firstPosition = mRecyclerView.getChildAdapterPosition(firstView);
View thisView = mRecyclerView.getChildAt(thisPosition - firstPosition);
int fromY = thisView.getTop();

mRecyclerView.smoothScrollBy(0, fromY - toY);

빠른 솔루션을 위해 충분히 잘 작동하는 것 같습니다.


1
의 가치는 무엇입니까 thisPosition?
pRaNaY

그것은 당신이 부드럽게 스크롤하려는 위치입니다
Jan Rabe

계산없이 smoothScrollToPosition (int position)을 사용하지 않는 이유는 무엇입니까? 어디서부터 시작하든 상관 없습니다.
놀라운 1
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.